diff --git a/changelogs/unreleased/gh-9895-forbid-empty-group-or-replicaset.md b/changelogs/unreleased/gh-9895-forbid-empty-group-or-replicaset.md
new file mode 100644
index 0000000000000000000000000000000000000000..5b47bf8e3218b27f8ec07cf32384620a444a1297
--- /dev/null
+++ b/changelogs/unreleased/gh-9895-forbid-empty-group-or-replicaset.md
@@ -0,0 +1,5 @@
+## bugfix/config
+
+* Added additional validation to a cluster's configuration.
+  Now it is forbidden to create an empty group or
+  replicaset (gh-9895).
diff --git a/src/box/lua/config/configdata.lua b/src/box/lua/config/configdata.lua
index 81321b9d4ef052ec7e63c0956666530004caa3e1..d83fb18d2bc930e96411ad59baff11170c31a42c 100644
--- a/src/box/lua/config/configdata.lua
+++ b/src/box/lua/config/configdata.lua
@@ -731,12 +731,32 @@ local function validate_anon(found, peers, failover, leader)
     end
 end
 
+local function validate_misplacing(cconfig)
+    for group_name, group_cfg in pairs(cconfig.groups) do
+        if group_cfg.replicasets == nil or
+                next(group_cfg.replicasets) == nil then
+            error(('group %q should include at ' ..
+                   'least one replicaset.'):format(group_name), 0)
+        end
+
+        for replicaset_name, replicaset_cfg in pairs(group_cfg.replicasets) do
+            if replicaset_cfg.instances == nil or
+                    next(replicaset_cfg.instances) == nil then
+                error(('replicaset %q should include at ' ..
+                       'least one instance.'):format(replicaset_name), 0)
+            end
+        end
+    end
+end
+
 local function new(iconfig, cconfig, instance_name)
     -- Find myself in a cluster config, determine peers in the same
     -- replicaset.
     local found = cluster_config:find_instance(cconfig, instance_name)
     assert(found ~= nil)
 
+    validate_misplacing(cconfig)
+
     -- Precalculate configuration with applied defaults.
     local iconfig_def = instance_config:apply_default(iconfig)
 
diff --git a/test/config-luatest/cluster_config_test.lua b/test/config-luatest/cluster_config_test.lua
index 075263962af0593503337f275efb6a4561831786..26d41bb922a22dd6831822bfbd3e451b5ef98142 100644
--- a/test/config-luatest/cluster_config_test.lua
+++ b/test/config-luatest/cluster_config_test.lua
@@ -281,3 +281,33 @@ g.test_instance_uri_errors = function(g)
         end)
     end)
 end
+
+-- Attempt to pass an empty group and an empty replicaset.
+g.test_misplace_option = function(g)
+    local config = cbuilder.new()
+        :use_group('g-001')
+
+        :use_replicaset('r-001')
+        :add_instance('i-001', {})
+
+        :use_group('sharding')
+        :set_group_option('roles', {'storage'})
+        :config()
+
+    cluster.startup_error(g, config, "group \"sharding\" should " ..
+                                     "include at least one replicaset.")
+
+    local config = cbuilder.new()
+        :use_group('g-001')
+
+        :use_replicaset('r-001')
+        :add_instance('i-001', {})
+
+        :use_replicaset('sharding')
+        :set_replicaset_option('roles', {'storage'})
+
+        :config()
+
+    cluster.startup_error(g, config, "replicaset \"sharding\" should " ..
+                                     "include at least one instance.")
+end