hyperledger/fabric · error

metadata has nil consenter

Error message

metadata has nil consenter

What it means

While iterating over the consenters, a nil entry in metadata.GetConsenters() is rejected: every consenter must carry host, port and TLS certs. This indicates malformed metadata rather than an invalid certificate (that produces a different wrapped error).

Source

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

	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
}

func parseCertificateFromBytes(cert []byte) (*x509.Certificate, error) {
	pemBlock, _ := pem.Decode(cert)
	if pemBlock == nil {
		return &x509.Certificate{}, errors.Errorf("no PEM data found in cert[% x]", cert)
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Remove nil entries and populate each Consenter with Host, Port, ServerTlsCert and ClientTlsCert.
  2. Check the code path that builds Consenters for accidental nil appends.
  3. Pre-validate the slice with a loop checking each element non-nil before calling VerifyConfigMetadata.

Example fix

// before
consenters = append(consenters, nilConsenterMaybe())
// after
if c := buildConsenter(); c != nil { consenters = append(consenters, c) }
Defensive patterns

Strategy: type-guard

Validate before calling

for i, c := range metadata.GetConsenters() {
	if c == nil {
		return fmt.Errorf("consenter at index %d is nil", i)
	}
}

Type guard

func allConsentersPresent(m *etcdraft.ConfigMetadata) bool {
	for _, c := range m.GetConsenters() {
		if c == nil || c.GetHost() == "" || c.GetPort() == 0 {
			return false
		}
	}
	return len(m.GetConsenters()) > 0
}

Try / catch

if err := VerifyConfigMetadata(meta, opts); err != nil {
	if strings.Contains(err.Error(), "nil consenter") {
		return errors.New("config-generation bug: nil entry in Consenters list")
	}
	return err
}

Prevention

When it happens

Trigger: A ConfigMetadata whose Consenters slice contains a nil element, typically from buggy config-generation code or partial protobuf decoding.

Common situations: Programmatically appending consenters and appending a nil pointer; proto decoded with a consenter message that is present but empty and represented as nil in the slice.

Related errors


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