hyperledger/fabric · error
cannot create a block deliverer because height=0
Error message
cannot create a block deliverer because height=0
What it means
createBlockDelivererCFT builds a crash-fault-tolerant block deliverer for a channel and requires the local ledger to be initialized. Before constructing the deliverer it reads the ledger height via blocksprovider.LedgerInfo.LedgerHeight(); if the ledger reports height 0 (no genesis block committed yet) there is no block to seek from, so it refuses to create a deliverer. This is a deliberate guard: the deliver service must know a starting block/hash to connect to an ordering service.
Source
Thrown at core/deliverservice/deliveryclient.go:175
go func() {
d.blockDeliverer.DeliverBlocks()
finalizer()
}()
return nil
}
func (d *deliverServiceImpl) createBlockDelivererCFT(chainID string, ledgerInfo blocksprovider.LedgerInfo) (*blocksprovider.Deliverer, error) {
height, err := ledgerInfo.LedgerHeight()
if err != nil {
return nil, errors.Wrapf(err, "cannot get ledger height")
}
currentBlockHash, err := ledgerInfo.GetCurrentBlockHash()
if err != nil {
return nil, errors.Wrapf(err, "cannot get current block hash")
}
if height == 0 {
return nil, errors.New("cannot create a block deliverer because height=0")
}
ubv, err := deliverclient.NewBlockVerificationAssistantFromConfig(
d.conf.ChannelConfig, height-1, currentBlockHash, chainID, d.conf.CryptoProvider, flogging.MustGetLogger("common.deliverclient.blockverification"),
)
if err != nil {
return nil, err
}
logger.Debugf("Created an updatable block verifier from ChannelConfig, height: %d,`%+v`", height, ubv)
logger.Infof("Creating a CFT (crash fault tolerant) BlockDeliverer for channel `%s`", chainID)
dc := &blocksprovider.Deliverer{
ChannelID: chainID,
BlockHandler: &GossipBlockHandler{
gossip: d.conf.Gossip,
blockGossipDisabled: !d.conf.DeliverServiceConfig.BlockGossipEnabled,
logger: flogging.MustGetLogger("peer.blocksprovider").With("channel", chainID),
},
Ledger: ledgerInfo,View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure the peer has joined the channel: commit the genesis block (peer channel join) and verify the ledger height is >= 1 before starting delivery
- Wait/retry delivery startup until the ledger is initialized (height >= 1) instead of starting it immediately after channel creation
- Check the peer logs and ledger data directory for corruption or an incomplete join; if damaged, re-join the channel from the genesis block
- If the ledger is empty because of a restore, restore the ledger data (or re-join and let gossip/state sync catch up) before enabling the deliver service
Example fix
// before: start deliver as soon as channel is known
svc.StartDeliverForChannel(chainID, "myclient", identity)
// after: wait for the ledger to be initialized
for {
h, err := ledgerInfo.LedgerHeight()
if err == nil && h > 0 {
break
}
time.Sleep(time.Second)
}
svc.StartDeliverForChannel(chainID, "myclient", identity) Defensive patterns
Strategy: validation
Validate before calling
height, err := ledgerInfo.LedgerHeight()
if err != nil {
return fmt.Errorf("ledger not readable for %s: %w", chainID, err)
}
if height == 0 {
return fmt.Errorf("channel %s ledger empty; join genesis block before starting delivery", chainID)
} Type guard
func ledgerReady(h uint64, err error) bool {
return err == nil && h > 0
} Try / catch
err := deliverSvc.StartDeliverForChannel(chainID, clientName, identity)
if err != nil && strings.Contains(err.Error(), "height=0") {
// ledger not initialized; schedule retry after genesis commit
} Prevention
- Always join the channel (commit genesis) before wiring the deliver service
- Poll LedgerHeight() until >= 1 as a readiness gate
- Alert on peers whose channel membership exists but ledger height stays 0
- Avoid wiping ledger data directories without re-joining channels
When it happens
Trigger: Calling StartDeliverForChannel (which calls createBlockDelivererCFT) while the peer's ledger for that channel has LedgerHeight() == 0 — i.e. the channel's genesis block has not been joined/committed on this peer.
Common situations: Peer started before joining the channel; genesis block join transaction failed or was retried; peer storage (ledger data) was wiped or partially restored so the channel exists in config but the ledger is empty; a race where delivery is started immediately after channel creation before the genesis commit lands.
Related errors
- error decoding the block number
- error decoding the data hash
- error decoding the previous hash
- error decoding the length of block data
- error decoding the transaction envelope
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/d4febdeb617c2ea9.
Report an issue: GitHub.