hyperledger/fabric · warning
context finished before block retrieved
Error message
context finished before block retrieved
What it means
deliverBlocks waits on a select for the next block, context cancellation, or a consensus error. When ctx is canceled or times out while waiting for the iterator's next block, the handler returns INTERNAL_SERVER_ERROR wrapping ctx.Err() with this message.
Source
Thrown at common/deliver/deliver.go:310
if number > chain.Reader().Height()-1 {
logger.Warningf("[channel: %s] Block %d not found, block number greater than chain length bounds", chdr.ChannelId, number)
return cb.Status_NOT_FOUND, nil
}
}
var block *cb.Block
var status cb.Status
iterCh := make(chan struct{})
go func() {
block, status = cursor.Next()
close(iterCh)
}()
select {
case <-ctx.Done():
logger.Debugf("Context canceled, aborting wait for next block")
return cb.Status_INTERNAL_SERVER_ERROR, errors.Wrapf(ctx.Err(), "context finished before block retrieved")
case <-erroredChan:
// TODO, today, the only user of the errorChan is the orderer consensus implementations. If the peer ever reports
// this error, we will need to update this error message, possibly finding a way to signal what error text to return.
logger.Warningf("Aborting deliver for request because the backing consensus implementation indicates an error")
return cb.Status_SERVICE_UNAVAILABLE, nil
case <-iterCh:
// Iterator has set the block and status vars
}
if status != cb.Status_SUCCESS {
logger.Warningf("[channel: %s] Error reading from channel, cause was: %v", chdr.ChannelId, status)
return status, nil
}
// increment block number to support FAIL_IF_NOT_READY deliver behavior
number++
if err := accessControl.Evaluate(); err != nil {View on GitHub (pinned to 2736b63f8f)
Solutions
- Increase the client's gRPC deadline/timeout for the deliver stream
- Seek to a valid, existing block height (e.g., oldest/newest) rather than waiting on an unproduced height
- Check orderer health (consensus, Raft leader) and network connectivity; retry with backoff
Example fix
// before ctx := context.Background() stream, _ := client.Deliver(ctx) // no deadline // after ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() stream, _ := client.Deliver(ctx)
Defensive patterns
Strategy: try-catch
Validate before calling
if deadline, ok := ctx.Deadline(); ok && time.Until(deadline) < 30*time.Second {
return errors.New("deliver deadline too short; extend client timeout")
} Try / catch
status, err := deliverClient.Deliver(ctx, envelope)
if err != nil && strings.Contains(err.Error(), "context finished before block retrieved") {
if errors.Is(err, context.DeadlineExceeded) {
return retryWithLongerDeadline(ctx)
}
return err // explicit cancel
} Prevention
- Use generous deadlines on deliver streams (blocks may be slow to produce)
- Retry with exponential backoff on context deadline errors
- Check orderer/consensus health when waits are frequently interrupted
When it happens
Trigger: Client context deadline exceeded or explicit cancel while the deliver stream is blocked waiting for the next block from the ledger iterator.
Common situations: Client-side gRPC deadline too short relative to block production rate; seek on a height that isn't produced for a long time; orderer slow to commit; network partitions.
Related errors
- message is nil
- timed out waiting for connection to deliver on all peers
- timed out waiting for txid on all peers
- error receiving
- error receiving from peer deliver service
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/9abb2596055b8676.
Report an issue: GitHub.