hyperledger/fabric · error
timeout expired while executing transaction
Error message
timeout expired while executing transaction
What it means
Returned by Handler.execute when waiting for the chaincode's response exceeds the configured execution timeout. The handler abandons waiting on txctx.ResponseNotifier, records an ExecuteTimeouts metric, and fails the transaction with ErrorExecutionTimeout ('timeout expired while executing transaction').
Source
Thrown at core/chaincode/handler.go:1449
txctx, err := h.TXContexts.Create(txParams)
if err != nil {
return nil, err
}
defer h.TXContexts.Delete(msg.ChannelId, msg.Txid)
if err = h.setChaincodeProposal(txParams.SignedProp, txParams.Proposal, msg); err != nil {
return nil, err
}
h.serialSendAsync(msg)
var ccresp *pb.ChaincodeMessage
select {
case ccresp = <-txctx.ResponseNotifier:
// response is sent to user or calling chaincode. ChaincodeMessage_ERROR
// are typically treated as error
case <-time.After(timeout):
err = errors.New(ErrorExecutionTimeout)
h.Metrics.ExecuteTimeouts.With("chaincode", h.chaincodeID).Add(1)
case <-h.streamDone():
err = errors.New(ErrorStreamTerminated)
}
return ccresp, err
}
func (h *Handler) setChaincodeProposal(signedProp *pb.SignedProposal, prop *pb.Proposal, msg *pb.ChaincodeMessage) error {
if prop != nil && signedProp == nil {
return errors.New("failed getting proposal context. Signed proposal is nil")
}
// TODO: This doesn't make a lot of sense. Feels like both are required or
// neither should be set. Check with a knowledgeable expert.
if prop != nil {
msg.Proposal = signedProp
}
return nilView on GitHub (pinned to 2736b63f8f)
Solutions
- Increase core.chaincode.executetimeout in the peer configuration (e.g. 60s/120s).
- Profile and optimize the chaincode — move slow external I/O out of the transaction path.
- Check chaincode container logs/health for hangs, OOM kills, or crashes.
- Ensure the chaincode responds to every transaction; add deadline handling inside the chaincode.
Example fix
// before (core.yaml) core.chaincode.executetimeout: 30s // after core.chaincode.executetimeout: 120s
Defensive patterns
Strategy: retry
Validate before calling
// size the timeout to the workload in core.yaml core.chaincode.executetimeout: 120s // measure worst-case chaincode latency first
Try / catch
if err != nil && strings.Contains(err.Error(), "timeout expired") {
// check chaincode logs, then resubmit with increased timeout
return fmt.Errorf("transaction timed out; check chaincode performance: %w", err)
} Prevention
- Benchmark chaincode latency and set executetimeout above the p99.
- Keep external I/O (HTTP calls, etc.) out of transaction logic.
- Alert on the ExecuteTimeouts metric to catch degraded chaincodes.
When it happens
Trigger: The select in Handler.execute hits `case <-time.After(timeout)` because the chaincode container never sent a response message before the timeout (core.chaincode.executetimeout, default 30s) elapsed.
Common situations: Chaincode doing heavy computation or long external calls (HTTP, DB); chaincode container hung or OOM-killed; slow peer/CCaaS startup; core.chaincode.executetimeout set too low for the workload.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- failed to execute transaction %s
- invalid chaincode ID
- First message needs to be a register
- TLS is active but chaincode %s didn't send certificate
- Chaincode %s with given certificate hash %v not found in reg
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/24c8390a646a909d.
Report an issue: GitHub.