{"record":{"id":"24c8390a646a909d","repo":"hyperledger/fabric","slug":"timeout-expired-while-executing-transaction","errorCode":null,"errorMessage":"timeout expired while executing transaction","messagePattern":"timeout expired while executing transaction","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/chaincode/handler.go","lineNumber":1449,"sourceCode":"\ttxctx, err := h.TXContexts.Create(txParams)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer h.TXContexts.Delete(msg.ChannelId, msg.Txid)\n\n\tif err = h.setChaincodeProposal(txParams.SignedProp, txParams.Proposal, msg); err != nil {\n\t\treturn nil, err\n\t}\n\n\th.serialSendAsync(msg)\n\n\tvar ccresp *pb.ChaincodeMessage\n\tselect {\n\tcase ccresp = <-txctx.ResponseNotifier:\n\t\t// response is sent to user or calling chaincode. ChaincodeMessage_ERROR\n\t\t// are typically treated as error\n\tcase <-time.After(timeout):\n\t\terr = errors.New(ErrorExecutionTimeout)\n\t\th.Metrics.ExecuteTimeouts.With(\"chaincode\", h.chaincodeID).Add(1)\n\tcase <-h.streamDone():\n\t\terr = errors.New(ErrorStreamTerminated)\n\t}\n\n\treturn ccresp, err\n}\n\nfunc (h *Handler) setChaincodeProposal(signedProp *pb.SignedProposal, prop *pb.Proposal, msg *pb.ChaincodeMessage) error {\n\tif prop != nil && signedProp == nil {\n\t\treturn errors.New(\"failed getting proposal context. Signed proposal is nil\")\n\t}\n\t// TODO: This doesn't make a lot of sense. Feels like both are required or\n\t// neither should be set. Check with a knowledgeable expert.\n\tif prop != nil {\n\t\tmsg.Proposal = signedProp\n\t}\n\treturn nil","sourceCodeStart":1431,"sourceCodeEnd":1467,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/chaincode/handler.go#L1431-L1467","documentation":"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').","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (core.yaml)\ncore.chaincode.executetimeout: 30s\n// after\ncore.chaincode.executetimeout: 120s","handlingStrategy":"retry","validationCode":"// size the timeout to the workload in core.yaml\ncore.chaincode.executetimeout: 120s // measure worst-case chaincode latency first","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"timeout expired\") {\n    // check chaincode logs, then resubmit with increased timeout\n    return fmt.Errorf(\"transaction timed out; check chaincode performance: %w\", err)\n}","preventionTips":["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."],"tags":["hyperledger-fabric","chaincode","timeout","transaction"],"backgroundTag":"execution-timeout","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}