hyperledger/fabric · error

supplied system channel group has no sub-groups

Error message

supplied system channel group has no sub-groups

What it means

ConfigTemplateFromGroup clones an existing system-channel config group and adapts it into a template for a new channel. If the cloned group has no Groups map at all, it cannot be a system channel group, so the library rejects it with this error. It protects against passing an empty or non-system-channel group.

Source

Thrown at internal/configtxgen/encoder/encoder.go:506

	channelGroup, err := NewChannelGroup(conf)
	if err != nil {
		return nil, errors.WithMessage(err, "error parsing configuration")
	}

	if _, ok := channelGroup.Groups[channelconfig.ApplicationGroupKey]; !ok {
		return nil, errors.New("channel template configs must contain an application section")
	}

	channelGroup.Groups[channelconfig.ApplicationGroupKey].Values = nil
	channelGroup.Groups[channelconfig.ApplicationGroupKey].Policies = nil

	return channelGroup, nil
}

func ConfigTemplateFromGroup(conf *genesisconfig.Profile, cg *cb.ConfigGroup) (*cb.ConfigGroup, error) {
	template := proto.Clone(cg).(*cb.ConfigGroup)
	if template.Groups == nil {
		return nil, errors.Errorf("supplied system channel group has no sub-groups")
	}

	template.Groups[channelconfig.ApplicationGroupKey] = &cb.ConfigGroup{
		Groups: map[string]*cb.ConfigGroup{},
		Policies: map[string]*cb.ConfigPolicy{
			channelconfig.AdminsPolicyKey: {},
		},
	}

	consortiums, ok := template.Groups[channelconfig.ConsortiumsGroupKey]
	if !ok {
		return nil, errors.Errorf("supplied system channel group does not appear to be system channel (missing consortiums group)")
	}

	if consortiums.Groups == nil {
		return nil, errors.Errorf("system channel consortiums group appears to have no consortiums defined")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Pass the ChannelGroup from the ordering system channel's current config (e.g. via the orderer's channel config retrieval).
  2. Check that the group actually has Orderer/Consortiums/Application sub-groups before calling.
  3. If constructing programmatically, build the group with NewChannelGroup for the system channel profile first.

Example fix

// before
var cg *cb.ConfigGroup
template, err := encoder.ConfigTemplateFromGroup(profile, cg)
// after
cg, err := fetchSystemChannelGroup(ordererClient) // must contain sub-groups
template, err := encoder.ConfigTemplateFromGroup(profile, cg)
Defensive patterns

Strategy: type-guard

Validate before calling

if cg == nil || cg.Groups == nil || len(cg.Groups) == 0 {
    return errors.New("supplied group must be a populated system channel group")
}

Type guard

func isSystemChannelLikeGroup(cg *cb.ConfigGroup) bool {
    return cg != nil && cg.Groups != nil && len(cg.Groups) > 0
}

Try / catch

tmpl, err := encoder.ConfigTemplateFromGroup(profile, cg)
if err != nil && strings.Contains(err.Error(), "no sub-groups") {
    return errors.New("fetch the system channel config, not an empty group")
}

Prevention

When it happens

Trigger: Calling ConfigTemplateFromGroup / MakeChannelCreationTransactionWithSystemChannelContext with a cb.ConfigGroup whose Groups map is nil — e.g. a nil or freshly constructed config group, or the group of a channel that has no sub-groups.

Common situations: Passing the config group of an application channel (or an empty group) instead of the ordering system channel's group when creating channels programmatically.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/45d2f9d1b589633e. Report an issue: GitHub.