hyperledger/fabric · warning
block deliverer for channel `%s` is <nil>, can't stop delive
Error message
block deliverer for channel `%s` is <nil>, can't stop delivery
What it means
StopDeliverForChannel returns this error when d.blockDeliverer is nil, meaning no active block deliverer exists for the channel to stop. This happens if delivery was never started for the channel or a previous stop already cleared the deliverer.
Source
Thrown at core/deliverservice/deliveryclient.go:310
return dcBFT, nil
}
// StopDeliverForChannel stops blocks delivery for channel by stopping channel block provider
func (d *deliverServiceImpl) StopDeliverForChannel() error {
d.lock.Lock()
defer d.lock.Unlock()
if d.stopping {
errMsg := fmt.Sprintf("block deliverer for channel `%s` is already stopped", d.channelID)
logger.Errorf("Delivery service: %s", errMsg)
return errors.New(errMsg)
}
if d.blockDeliverer == nil {
errMsg := fmt.Sprintf("block deliverer for channel `%s` is <nil>, can't stop delivery", d.channelID)
logger.Errorf("Delivery service: %s", errMsg)
return errors.New(errMsg)
}
d.blockDeliverer.Stop()
d.blockDeliverer = nil
logger.Debugf("This peer will stop passing blocks from orderer service to other peers on channel: %s", d.channelID)
return nil
}
// Stop all service and release resources
func (d *deliverServiceImpl) Stop() {
d.lock.Lock()
defer d.lock.Unlock()
// Marking flag to indicate the shutdown of the delivery service
d.stopping = true
if d.blockDeliverer != nil {
d.blockDeliverer.Stop()
d.blockDeliverer = nilView on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure StartDeliverForChannel succeeded before calling StopDeliverForChannel for that channel
- Treat the error as benign if stop is intended to be idempotent and skip it
- Check logs for an earlier start failure (e.g. 'failed to access client TLS configuration') that left the deliverer nil
- Fix the channel ID / lifecycle ordering so stop only runs on started channels
Example fix
// before
service.StopDeliverForChannel(channelID) // may fail if never started
// after
if err := service.StopDeliverForChannel(channelID); err != nil &&
strings.Contains(err.Error(), "is <nil>") {
logger.Debugf("channel %s was not started; nothing to stop", channelID)
} Defensive patterns
Strategy: validation
Validate before calling
if !startedChannels[channelID] {
return fmt.Errorf("channel %s was never started", channelID)
} Type guard
func isNilDelivererErr(err error) bool {
return err != nil && strings.Contains(err.Error(), "is <nil>")
} Try / catch
if err := svc.StopDeliverForChannel(ch); err != nil {
if isNilDelivererErr(err) {
logger.Debugf("nothing to stop for %s", ch)
return nil
}
return err
} Prevention
- Only stop channels whose StartDeliverForChannel returned success
- Handle start failures before entering stop/shutdown paths
- Log channel lifecycle transitions to spot out-of-order start/stop
When it happens
Trigger: Calling StopDeliverForChannel(channelID) when StartDeliverForChannel was never called for that channel, or after a prior StopDeliverForChannel already set d.blockDeliverer = nil, or if start failed earlier (e.g. error 830).
Common situations: Stopping a channel that failed to start due to a TLS/config error; calling stop on a typo'd or removed channel ID; shutdown paths running after an earlier stop cleared state.
Related errors
- 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
- private data APIs are not allowed in chaincode Init()
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/02332802879d01a6.
Report an issue: GitHub.