hyperledger/fabric · error

cannot enable channel capabilities without orderer support f

Error message

cannot enable channel capabilities without orderer support first

What it means

Fabric enforces a strict capability upgrade ordering: orderer nodes must first support a capability before channel-level capabilities that require it can be enabled. preValidate rejects any config that sets ChannelGroup.Values[CapabilitiesKey] while the Orderer group lacks a Capabilities value. This prevents orderers running older binaries from being handed config they cannot process.

Source

Thrown at common/channelconfig/bundle.go:245

		policyManager:   policyManager,
		channelConfig:   channelConfig,
		configtxManager: configtxManager,
	}, nil
}

func preValidate(config *cb.Config) error {
	if config == nil {
		return errors.New("channelconfig Config cannot be nil")
	}

	if config.ChannelGroup == nil {
		return errors.New("config must contain a channel group")
	}

	if og, ok := config.ChannelGroup.Groups[OrdererGroupKey]; ok {
		if _, ok := og.Values[CapabilitiesKey]; !ok {
			if _, ok := config.ChannelGroup.Values[CapabilitiesKey]; ok {
				return errors.New("cannot enable channel capabilities without orderer support first")
			}

			if ag, ok := config.ChannelGroup.Groups[ApplicationGroupKey]; ok {
				if _, ok := ag.Values[CapabilitiesKey]; ok {
					return errors.New("cannot enable application capabilities without orderer support first")
				}
			}
		}
	}

	return nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. First perform a config update adding the capability only to the Orderer group (and roll out upgraded orderer binaries), then a second update adding it to the channel group
  2. Edit configtx.yaml so Orderer: Capabilities is set to the target version and re-run configtxgen before touching channel capabilities
  3. Use configtxlator to decode the current config, add the capability under groups.Orderer.values, and submit that update first

Example fix

// before (single-step: channel capability without orderer capability)
config.ChannelGroup.Values["Capabilities"] = &cb.ConfigValue{...} // rejected

// after (two-step; step 1 shown)
og := config.ChannelGroup.Groups["Orderer"]
og.Values["Capabilities"] = &cb.ConfigValue{
    Value: protoutil.MarshalOrPanic(&cb.Capabilities{Capabilities: []string{"V2_0"}}),
}
// submit; then add the same capability to ChannelGroup.Values
Defensive patterns

Strategy: validation

Validate before calling

func ordererCapsPresent(cfg *cb.Config) bool {
    if cfg.ChannelGroup == nil { return false }
    _, hasChannelCaps := cfg.ChannelGroup.Values["Capabilities"]
    og, ok := cfg.ChannelGroup.Groups["Orderer"]
    if !hasChannelCaps { return true }
    return ok && og.Values != nil && og.Values["Capabilities"] != nil
}
if !ordererCapsPresent(cfg) { return errors.New("enable orderer capabilities first") }

Try / catch

if err := updateChannelConfig(cfg); err != nil {
    if strings.Contains(err.Error(), "without orderer support first") {
        return fmt.Errorf("split into two updates: orderer capability first, then channel capability")
    }
    return err
}

Prevention

When it happens

Trigger: Submitting a channel config update that adds a capability (e.g. V2_0) to the channel group when config.ChannelGroup.Groups[OrdererGroupKey].Values has no CapabilitiesKey entry — typically a single-step upgrade attempted via configtxlator or configtxgen.

Common situations: Upgrading a network from v1.4 to v2.x and trying to enable channel capabilities in one step; regenerating channel config with an upgraded configtx.yaml capabilities section but forgetting the orderer group; scripts that patch only the channel group in the decoded config.

Related errors


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