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

  1. Ensure the peer has joined the channel: commit the genesis block (peer channel join) and verify the ledger height is >= 1 before starting delivery
  2. Wait/retry delivery startup until the ledger is initialized (height >= 1) instead of starting it immediately after channel creation
  3. Check the peer logs and ledger data directory for corruption or an incomplete join; if damaged, re-join the channel from the genesis block
  4. 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

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


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/d4febdeb617c2ea9. Report an issue: GitHub.