hyperledger/fabric · error
nil response from transaction %s
Error message
nil response from transaction %s
What it means
processChaincodeExecutionResult raises this when the Invoke call returned no error but also no ChaincodeMessage response (resp == nil). The peer expected a well-formed chaincode response message to convert into a pb.Response; a nil response means the execution produced nothing usable, which the peer treats as a hard error for the transaction.
Source
Thrown at core/chaincode/chaincode_support.go:178
return nil, nil, err
}
resp, err := cs.execute(pb.ChaincodeMessage_INIT, txParams, ccName, input, h)
return processChaincodeExecutionResult(txParams.TxID, ccName, resp, err)
}
// Execute invokes chaincode and returns the original response.
func (cs *ChaincodeSupport) Execute(txParams *ccprovider.TransactionParams, chaincodeName string, input *pb.ChaincodeInput) (*pb.Response, *pb.ChaincodeEvent, error) {
resp, err := cs.Invoke(txParams, chaincodeName, input)
return processChaincodeExecutionResult(txParams.TxID, chaincodeName, resp, err)
}
func processChaincodeExecutionResult(txid, ccName string, resp *pb.ChaincodeMessage, err error) (*pb.Response, *pb.ChaincodeEvent, error) {
if err != nil {
return nil, nil, errors.Wrapf(err, "failed to execute transaction %s", txid)
}
if resp == nil {
return nil, nil, errors.Errorf("nil response from transaction %s", txid)
}
if resp.ChaincodeEvent != nil {
resp.ChaincodeEvent.ChaincodeId = ccName
resp.ChaincodeEvent.TxId = txid
}
switch resp.Type {
case pb.ChaincodeMessage_COMPLETED:
res := &pb.Response{}
err := proto.Unmarshal(resp.Payload, res)
if err != nil {
return nil, nil, errors.Wrapf(err, "failed to unmarshal response for transaction %s", txid)
}
return res, resp.ChaincodeEvent, nil
case pb.ChaincodeMessage_ERROR:
return nil, resp.ChaincodeEvent, errors.Errorf("transaction returned with failure: %s", resp.Payload)View on GitHub (pinned to 2736b63f8f)
Solutions
- Check peer and chaincode logs around the txid for a container exit or handler teardown that dropped the response.
- Retry the transaction; transient races or mid-invocation container death usually do not recur once the chaincode is healthy.
- Redeploy/fix the chaincode if its process exits during execution (OOM, panic), ensuring responses are always emitted.
- If reproducible with a system chaincode, check that chaincode's registration and execute path for a bug and report/patch it.
Example fix
// before: chaincode function can return without emitting a response when a resource is missing
func (s *SmartContract) GetAsset(ctx, id string) { if id == "" { return } ... }
// after: always return a response or an explicit error
func (s *SmartContract) GetAsset(ctx, id string) (*Asset, error) {
if id == "" { return nil, fmt.Errorf("id required") }
...
} Defensive patterns
Strategy: type-guard
Validate before calling
// Ensure chaincode functions always return a value or error, never fall through silently // go vet / staticcheck on chaincode to catch missing return paths
Type guard
func IsNilResponseError(err error) bool {
return err != nil && strings.Contains(err.Error(), "nil response from transaction")
} Try / catch
resp, err := contract.EvaluateTransaction("readAsset", "a1")
if err != nil {
if IsNilResponseError(err) {
// retry once; often caused by a transient handler/container race
resp, err = contract.EvaluateTransaction("readAsset", "a1")
}
return resp, err
} Prevention
- Ensure every chaincode function path returns a response or explicit error.
- Guard against OOM/panics that kill the chaincode mid-invocation.
- Add panic recovery in chaincode so a recovered panic still emits an error response.
- Test chaincode with edge-case inputs to catch silent no-return paths.
When it happens
Trigger: cs.Invoke returns (nil, nil): an internal path where the chaincode handler completed without delivering a response message — e.g. handler state inconsistencies, chaincode shutting down mid-invocation, or unexpected success-with-no-message from the internal execute path.
Common situations: Chaincode container terminating during the invocation so the response is lost; system/in-process chaincode that returns without emitting a response message; rare internal races in the handler registry during concurrent transactions on the same chaincode.
Related errors
- 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
- Chaincode %s with given certificate hash %v belongs to a dif
- Recv() error: %v, closing connection
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/66dd5f5d63091f27.
Report an issue: GitHub.