hyperledger/fabric · error

empty consenter set

Error message

empty consenter set

What it means

A Raft channel must have at least one consenter (ordering node). VerifyConfigMetadata returns this error when metadata.GetConsenters() is empty, since a cluster with zero nodes cannot elect a leader or replicate the ledger.

Source

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

		// 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)
	} else if d == 0 {
		return errors.Errorf("TickInterval cannot be zero")
	}

	if len(metadata.GetConsenters()) == 0 {
		return errors.Errorf("empty consenter set")
	}

	// verifying certificates for being signed by CA, expiration is ignored
	for _, consenter := range metadata.GetConsenters() {
		if consenter == nil {
			return errors.Errorf("metadata has nil consenter")
		}
		if err := validateConsenterTLSCerts(consenter, verifyOpts, true); err != nil {
			return errors.WithMessagef(err, "consenter %s:%d has invalid certificate", consenter.GetHost(), consenter.GetPort())
		}
	}

	if err := MetadataHasDuplication(metadata); err != nil {
		return err
	}

	return nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Include at least one Consenter (host, port, client/server TLS certs) in ConfigMetadata.
  2. If removing nodes, keep the remaining set non-empty and follow orderly consenter-exit procedures.
  3. Regenerate config via configtxgen with the Raft orderer profiles listing the orderers.

Example fix

// before
Consenters: []*Consenter{}
// after
Consenters: []*Consenter{{Host: "orderer.example.com", Port: 7050, ClientTlsCert: c, ServerTlsCert: s}}
Defensive patterns

Strategy: validation

Validate before calling

if len(metadata.GetConsenters()) == 0 {
	return errors.New("channel config must define at least one raft consenter")
}

Try / catch

if err := VerifyConfigMetadata(meta, opts); err != nil {
	if strings.Contains(err.Error(), "empty consenter set") {
		return errors.New("cannot remove all ordering nodes from a raft channel")
	}
	return err
}

Prevention

When it happens

Trigger: A config update removes all consenters, or a ConfigMetadata is constructed with only Options but no Consenter entries.

Common situations: Attempting to shrink an ordering service to zero nodes; hand-built metadata for tests; consenters list dropped during channel-create config generation.

Related errors


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