hyperledger/fabric · error
consenter options type mismatch
Error message
consenter options type mismatch
What it means
MarshalBFTOptions clones the smartbft.Options via proto.Clone and type-asserts the result back to *smartbft.Options; the assertion failing yields this error. With correct proto types the assertion always succeeds, so this indicates op is nil or not actually a *smartbft.Options (wrong concrete type or unregistered proto type). Thrown from the public MarshalBFTOptions, called by NewOrdererGroup.
Source
Thrown at common/channelconfig/util.go:337
return nil, fmt.Errorf("cannot load client cert for consenter %s:%d: %s", c.GetHost(), c.GetPort(), err)
}
c.ClientTlsCert = clientCert
serverCert, err := os.ReadFile(string(c.GetServerTlsCert()))
if err != nil {
return nil, fmt.Errorf("cannot load server cert for consenter %s:%d: %s", c.GetHost(), c.GetPort(), err)
}
c.ServerTlsCert = serverCert
}
return proto.Marshal(copyMd)
}
// MarshalBFTOptions serializes smartbft options.
func MarshalBFTOptions(op *smartbft.Options) ([]byte, error) {
if copyMd, ok := proto.Clone(op).(*smartbft.Options); ok {
return proto.Marshal(copyMd)
} else {
return nil, errors.New("consenter options type mismatch")
}
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure a non-nil *smartbft.Options with the current fabric-protos smartbft types is passed to NewOrdererGroup / MarshalBFTOptions.
- Rebuild with a single consistent version of github.com/hyperledger/fabric-protos-go so there is no vendored duplicate smartbft package.
- Check the orderer config selection code path: BFT consensus must populate OrdererConfig with smartbft.Options, not etcdraft or another type's options.
- If marshaling manually, verify via reflection that op is *smartbft.Options before calling.
Example fix
// before
var op *smartbft.Options // nil
bytes, err := MarshalBFTOptions(op)
// after
op := &smartbft.Options{N: 1, ...}
bytes, err := MarshalBFTOptions(op) Defensive patterns
Strategy: type-guard
Validate before calling
func validBFTOptions(op *smartbft.Options) bool {
return op != nil
}
if !validBFTOptions(op) {
return errors.New("smartbft options must be non-nil")
} Type guard
func isSmartBFTOptions(m proto.Message) (*smartbft.Options, bool) {
op, ok := m.(*smartbft.Options)
if !ok || op == nil {
return nil, false
}
return op, true
} Try / catch
// errors are returned, not panicked
bytes, err := channelconfig.MarshalBFTOptions(op)
if err != nil {
return fmt.Errorf("marshal smartbft options: %w", err)
} Prevention
- Pass non-nil *smartbft.Options from the same fabric-protos version the library compiles against
- Avoid duplicating/vendoring fabric-protos-go — one type identity per import path
- Ensure the BFT orderer config path actually populates smartbft.Options (not another consensus type's options)
When it happens
Trigger: NewOrdererGroup with BFT orderer type where the options passed as *smartbft.Options are nil or are actually a different proto message type, so proto.Clone returns a clone that fails the *smartbft.Options assertion.
Common situations: Mixing smartbft versions/types where the compiled proto type differs from the one asserted; passing nil Options into orderer group creation; custom builds with renamed or vendored smartbft packages producing two distinct Go types.
Related errors
- failed to deserialize values
- Unexpected key %s
- policy (name='%s',type='%T') is not convertible to Signature
- wrong chain type
- failed unmarshalling gossip envelope to alive message
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/1f152a85d0cee2f4.
Report an issue: GitHub.