hyperledger/fabric · error
orderer `%s` hung up without sending status
Error message
orderer `%s` hung up without sending status
What it means
ProcessIncoming reads deliver responses from br.recvC; when the channel closes (ok == false) the orderer terminated the deliver stream without sending a DeliveredStatus/Status message. The receiver logs a warning and returns errors.Errorf("orderer `%s` hung up without sending status") with the endpoint address. This aborts the current receive loop for that endpoint.
Source
Thrown at common/deliverclient/blocksprovider/block_receiver.go:103
close(br.stopC)
br.logger.Infof("BlockReceiver stopped")
}
// ProcessIncoming processes incoming messages until stopped or encounters an error.
func (br *BlockReceiver) ProcessIncoming(onSuccess func(blockNum uint64, channelConfig *common.Config)) error {
var err error
RecvLoop: // Loop until the endpoint is refreshed, or there is an error on the connection
for {
select {
case <-br.endpoint.Refreshed:
br.logger.Infof("Ordering endpoints have been refreshed, disconnecting from deliver to reconnect using updated endpoints")
err = &errRefreshEndpoint{message: fmt.Sprintf("orderer endpoint `%s` has been refreshed, ", br.endpoint.Address)}
break RecvLoop
case response, ok := <-br.recvC:
if !ok {
br.logger.Warningf("Orderer hung up without sending status")
err = errors.Errorf("orderer `%s` hung up without sending status", br.endpoint.Address)
break RecvLoop
}
var blockNum uint64
var channelConfig *common.Config
blockNum, channelConfig, err = br.processMsg(response)
if err != nil {
br.logger.Warningf("Got error while attempting to receive blocks: %v", err)
err = errors.WithMessagef(err, "got error while attempting to receive blocks from orderer `%s`", br.endpoint.Address)
break RecvLoop
}
onSuccess(blockNum, channelConfig)
case <-br.stopC:
br.logger.Infof("BlockReceiver got a signal to stop")
err = &ErrStopping{Message: "got a signal to stop"}
break RecvLoop
}
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Retry the connection — the block fetcher typically rotates to the next orderer endpoint; ensure retry/backoff logic is enabled and endpoints are diverse.
- Check orderer logs at the matching timestamp for crashes (panic, OOM kill) or graceful shutdown, and fix the underlying cause (e.g. memory limits).
- If behind a proxy/LB, increase idle timeouts or disable connection draining that cuts gRPC streams; use direct orderer access where possible.
- Verify keepalive settings on the gRPC client so half-open connections are detected and re-established.
Example fix
// before: single orderer endpoint, stream dies -> fetch fails ordererEndpoints: - orderer1.example.com:7050 // after: multiple endpoints so the fetcher reconnects to another orderer ordererEndpoints: - orderer1.example.com:7050 - orderer2.example.com:7050 - orderer3.example.com:7050
Defensive patterns
Strategy: retry
Validate before calling
// health-check the orderer stream target before ProcessIncoming
func ordererHealthy(addr string) error {
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
cc, err := grpc.DialContext(ctx, addr, grpc.WithBlock(), grpc.WithTransportCredentials(creds()))
if err != nil {
return fmt.Errorf("orderer %s unhealthy: %w", addr, err)
}
cc.Close()
return nil
} Try / catch
err := br.ProcessIncoming(ctx)
if err != nil {
if strings.Contains(err.Error(), "hung up without sending status") {
log.Warnf("orderer stream dropped (%v); rotating endpoint and retrying", err)
return retryWithNextEndpoint(ctx)
}
return err
} Prevention
- Configure gRPC keepalive to detect and recover dropped streams quickly.
- Avoid proxies/LBs with short idle timeouts in front of orderer deliver endpoints, or raise their timeouts.
- Ensure stable orderer infrastructure (adequate memory limits, graceful shutdown handling).
- Keep a multi-orderer endpoint list so the fetcher can reconnect elsewhere after a hang-up.
When it happens
Trigger: In FetchBlocks/DeliverBlocks, the gRPC deliver stream's Recv channel closes without delivering a final status: orderer process crash/restart, gRPC connection teardown, idle-timeout or max-stream limits, or an abrupt server-side disconnect mid-stream.
Common situations: Orderer pod restarted or crashed during block streaming; load balancer/proxy (e.g. ingress, ALB) killing idle gRPC connections; orderer shutting down for maintenance; network interruptions that close the TCP connection cleanly without a deliver status.
Related errors
- could not connect to ordering service
- could not connect to ordering service, orderer-address: %s
- failed sending proposal, due to %s
- Failed sending proposal, got %s
- failed to create new connection
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/874fa7e345e4609a.
Report an issue: GitHub.