hyperledger/fabric · error
block deliverer for channel `%s` already exists
Error message
block deliverer for channel `%s` already exists
What it means
StartDeliverForChannel returns this when a block deliverer is already registered on the DeliveryClient (d.blockDeliverer != nil), since Fabric's delivery client supports exactly one active deliverer per client instance. A second start request is rejected.
Source
Thrown at core/deliverservice/deliveryclient.go:115
// StartDeliverForChannel starts blocks delivery for channel
// initializes the grpc stream for given chainID, creates blocks provider instance
// that spawns in go routine to read new blocks starting from the position provided by ledger
// info instance.
func (d *deliverServiceImpl) StartDeliverForChannel(chainID string, ledgerInfo blocksprovider.LedgerInfo, finalizer func()) error {
d.lock.Lock()
defer d.lock.Unlock()
if d.stopping {
errMsg := fmt.Sprintf("block deliverer for channel `%s` is stopping", chainID)
logger.Errorf("Delivery service: %s", errMsg)
return errors.New(errMsg)
}
if d.blockDeliverer != nil {
errMsg := fmt.Sprintf("block deliverer for channel `%s` already exists", chainID)
logger.Errorf("Delivery service: %s", errMsg)
return errors.New(errMsg)
}
// TODO save the initial bundle in the block deliverer in order to maintain a stand alone BlockVerifier that gets updated
// immediately after a config block is pulled and verified.
bundle, err := channelconfig.NewBundle(chainID, d.conf.ChannelConfig, d.conf.CryptoProvider)
if err != nil {
return errors.WithMessagef(err, "failed to create block deliverer for channel `%s`", chainID)
}
oc, ok := bundle.OrdererConfig()
if !ok {
// This should never happen because it is checked in peer.createChannel()
return errors.Errorf("failed to create block deliverer for channel `%s`, missing OrdererConfig", chainID)
}
switch ct := oc.ConsensusType(); ct {
case "etcdraft":
d.blockDeliverer, err = d.createBlockDelivererCFT(chainID, ledgerInfo)
case "BFT":View on GitHub (pinned to 2736b63f8f)
Solutions
- Call StopDeliverForChannel before attempting to start again on the same client.
- Track started state in your code and make StartDeliverForChannel idempotent at the call site.
- Create a separate DeliveryClient instance if you need concurrent block delivery consumers.
- If caused by leader election retries, add a guard so only the elected leader starts delivery once.
Example fix
// before client.StartDeliverForChannel(chainID, f, stop) client.StartDeliverForChannel(chainID, f2, stop2) // error // after client.StartDeliverForChannel(chainID, f, stop) client.StopDeliverForChannel(chainID) client.StartDeliverForChannel(chainID, f2, stop2)
Defensive patterns
Strategy: validation
Validate before calling
var delivering atomic.Bool
if !delivering.CompareAndSwap(false, true) {
return errors.New("delivery already running")
}
err := client.StartDeliverForChannel(chainID, finalize, stopCh)
if err != nil {
delivering.Store(false)
} Try / catch
if err := client.StartDeliverForChannel(chainID, f, stopCh); err != nil {
if strings.Contains(err.Error(), "already exists") {
logger.Infof("deliverer already active for %s", chainID)
return nil
}
return err
} Prevention
- Stop the existing deliverer (StopDeliverForChannel) before starting a new one.
- Keep one deliverer per DeliveryClient; use separate clients for extra consumers.
- Make leader-election start calls idempotent/guarded with a flag.
- Avoid retrying Start blindly after failures — stop first, then start.
When it happens
Trigger: Calling StartDeliverForChannel twice for the same client without StopDeliverForChannel in between; two components (e.g. gossip leader and custom consumer) both starting delivery on one shared client.
Common situations: Leader-election flapping causing repeated start calls; application code retrying start after a transient failure without stopping first; sharing a single DeliveryClient across channel services.
Related errors
- chaincode already successfully installed (package ID '%s')
- failed listing installed chaincodes
- failed to parse collection config
- [channel %s] failed to get chaincode container info for %s
- chaincode '%s' does not require initialization but called as
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/847b8f7babec27e2.
Report an issue: GitHub.