hyperledger/fabric · error
without a system channel, a follower should have been create
Error message
without a system channel, a follower should have been created
What it means
In HandleChain, when the orderer has no system channel, a chain must start as a follower that discovers its identity from the channel's config block; only then can detectSelfID map the local TLS/identity cert to a consenter ID. If detectSelfID fails, this wrapper error is returned, indicating the follower/chain-bootstrapping path did not produce a recognizable local consenter certificate in the channel config.
Source
Thrown at orderer/consensus/smartbft/consenter.go:186
}
if smartBFTChain, isBFTSmart := cs.Chain.(*BFTChain); isBFTSmart {
return smartBFTChain
}
c.Logger.Warningf("Chain %s is of type %v and not smartbft.Chain", channelID, reflect.TypeOf(cs.Chain))
return nil
}
// HandleChain returns a new Chain instance or an error upon failure
func (c *Consenter) HandleChain(support consensus.ConsenterSupport, metadata *cb.Metadata) (consensus.Chain, error) {
consenters := support.SharedConfig().Consenters()
configOptions, err := createSmartBftConfig(support.SharedConfig())
if err != nil {
return nil, err
}
selfID, err := c.detectSelfID(consenters)
if err != nil {
return nil, errors.Wrap(err, "without a system channel, a follower should have been created")
}
c.Logger.Infof("Local consenter id is %d", selfID)
config, err := util.ConfigFromMetadataOptions(uint64(selfID), configOptions)
if err != nil {
return nil, errors.Wrap(err, "failed parsing smartbft configuration")
}
c.Logger.Debugf("SmartBFT-Go config: %+v", config)
configValidator := &ConfigBlockValidator{
ValidatingChannel: support.ChannelID(),
Filters: c.Registrar,
ConfigUpdateProposer: c.Registrar,
Logger: c.Logger,
}
egressCommFactory := func(runtimeConfig *atomic.Value, channelId string, comm cluster.Communicator) EgressComm {
channelDecorator := zap.String("channel", channelId)View on GitHub (pinned to 2736b63f8f)
Solutions
- Verify the orderer's General.TLS.Certificate and Cluster.ServerCertificate match a consenter entry (client_cert/server_cert) in the channel's Orderer.ConsenterMapping
- Re-issue the channel join with the correct latest config block: osnadmin channel join --channel-id ... --config-block <latest>
- Rotate or re-enroll the orderer's TLS/identity certs so they match the channel config, then restart the orderer
- Check detectSelfID's underlying error in the wrapped message for which cert (server/cluster/TLS) failed to match
Defensive patterns
Strategy: validation
Validate before calling
// Before joining, confirm local TLS certs appear in the channel's consenter mapping
block := fetchLatestConfigBlock(channelID)
consenters := extractConsenterMapping(block)
local := loadCert(ordererTLSPath)
if !containsCert(consenters, local) {
return fmt.Errorf("local TLS cert %s not in channel ConsenterMapping; update channel config first", ordererTLSPath)
} Try / catch
// HandleChain failure
chain, err := consenter.HandleChain(support, nil)
if err != nil {
if strings.Contains(err.Error(), "follower should have been created") {
log.Fatalf("local certs not in channel config: %v", err) // fix certs/block, don't retry blindly
}
return err
} Prevention
- Add the orderer's certs to the channel ConsenterMapping before joining
- Always join with the newest config block after cert rotations
- Keep General.TLS and Cluster certs identical and consistent across the cluster
- Validate the block with configtxlator before osnadmin channel join
When it happens
Trigger: Channel participation mode (no system channel) where HandleChain is invoked for a channel whose most recent config block's Orderer.ConsenterMapping does not contain a consenter whose server/cluster TLS certs match the local node's certificates, or detectSelfID fails on invalid PEM/TLS material.
Common situations: Using `osnadmin channel join` with TLS certificates on disk that don't match the certs enrolled in the channel config; joining a channel before the node's certs were added to the consenters list; misconfigured General.TLS / Cluster settings in orderer.yaml; stale join block after cert rotation.
Related errors
- nil block
- node identity certificate %s is not a valid PEM
- cannot get HeightsByEndpoints
- cannot create BFT block deliverer
- cannot get create BlockPuller
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/9bf9dbcd1f619dc6.
Report an issue: GitHub.