hyperledger/fabric · error

nil Raft config metadata options

Error message

nil Raft config metadata options

What it means

VerifyConfigMetadata requires the Options sub-message (HeartbeatTick, ElectionTick, MaxInflightBlocks, TickInterval, etc.) to be present. This error means metadata.GetOptions() returned nil, i.e. the Raft options section is entirely missing from the ConfigMetadata.

Source

Thrown at orderer/consensus/etcdraft/util.go:214

	configUpdate, err := configtx.UnmarshalConfigUpdateFromPayload(payload)
	if err != nil {
		return nil, nil, errors.Wrap(err, "could not read config update")
	}

	return MetadataFromConfigUpdate(configUpdate)
}

// VerifyConfigMetadata validates Raft config metadata.
// Note: ignores certificates expiration.
func VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts x509.VerifyOptions) error {
	if metadata == nil {
		// defensive check. this should not happen as CheckConfigMetadata
		// should always be called with non-nil config metadata
		return errors.Errorf("nil Raft config metadata")
	}

	if metadata.GetOptions() == nil {
		return errors.Errorf("nil Raft config metadata options")
	}

	if metadata.GetOptions().GetHeartbeatTick() == 0 ||
		metadata.GetOptions().GetElectionTick() == 0 ||
		metadata.GetOptions().GetMaxInflightBlocks() == 0 {
		// if SnapshotIntervalSize is zero, DefaultSnapshotIntervalSize is used
		return errors.Errorf("none of HeartbeatTick (%d), ElectionTick (%d) and MaxInflightBlocks (%d) can be zero",
			metadata.GetOptions().GetHeartbeatTick(), metadata.GetOptions().GetElectionTick(), metadata.GetOptions().GetMaxInflightBlocks())
	}

	// check Raft options
	if metadata.GetOptions().GetElectionTick() <= metadata.GetOptions().GetHeartbeatTick() {
		return errors.Errorf("ElectionTick (%d) must be greater than HeartbeatTick (%d)",
			metadata.GetOptions().GetElectionTick(), metadata.GetOptions().GetHeartbeatTick())
	}

	if d, err := time.ParseDuration(metadata.GetOptions().GetTickInterval()); err != nil {
		return errors.Errorf("failed to parse TickInterval (%s) to time duration: %s", metadata.GetOptions().GetTickInterval(), err)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Regenerate channel config including a full etcdraft.Options block (TickInterval, ElectionTick, HeartbeatTick, MaxInflightBlocks, SnapshotIntervalSize).
  2. Use configtxgen/configtxlator to diff your config against a known-good Raft config and restore Options.
  3. Guard in code: verify meta.GetOptions() != nil before deeper validation.

Example fix

// before: metadata with only consenters
Conf metadata = Metadata{Consenters: consenterList}
// after
Conf metadata = Metadata{Consenters: consenterList, Options: &Options{TickInterval: "500ms", HeartbeatTick: 1, ElectionTick: 10, MaxInflightBlocks: 256}}
Defensive patterns

Strategy: validation

Validate before calling

if metadata.GetOptions() == nil {
	return errors.New("raft Options block missing from channel config metadata")
}

Type guard

func optionsPresent(m *etcdraft.ConfigMetadata) bool { return m != nil && m.GetOptions() != nil }

Try / catch

if err := VerifyConfigMetadata(meta, opts); err != nil {
	if strings.Contains(err.Error(), "metadata options") {
		return errors.New("channel config lacks raft options; regenerate config with configtxgen")
	}
	return err
}

Prevention

When it happens

Trigger: A ConfigMetadata was built without Options, or the serialized config metadata in the channel's ConsensusType had an empty/omitted options field.

Common situations: Hand-crafted or migrated channel config dropping the options block; config generated by tooling that only sets consenters; protobuf default-empty message unmarshalled from empty metadata bytes.

Related errors


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