hyperledger/fabric · error

failed to unmarshal response for transaction %s

Error message

failed to unmarshal response for transaction %s

What it means

This error is wrapped by processChaincodeExecutionResult when a chaincode message of type COMPLETED arrives, but its payload cannot be proto-unmarshaled into a pb.Response. It means the peer received a 'successful' completion message from the chaincode whose bytes are not a valid serialized Response (status, message, payload fields). The underlying proto error is wrapped so the txid is included. This usually indicates a corrupt or malformed payload produced by the chaincode side or an incompatible protobuf schema.

Source

Thrown at core/chaincode/chaincode_support.go:191

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)

	default:
		return nil, nil, errors.Errorf("unexpected response type %d for transaction %s", resp.Type, txid)
	}
}

// Invoke will invoke chaincode and return the message containing the response.
// The chaincode will be launched if it is not already running.
func (cs *ChaincodeSupport) Invoke(txParams *ccprovider.TransactionParams, chaincodeName string, input *pb.ChaincodeInput) (*pb.ChaincodeMessage, error) {
	ccid, cctype, err := cs.CheckInvocation(txParams, chaincodeName, input)
	if err != nil {
		return nil, errors.WithMessage(err, "invalid invocation")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect the chaincode: ensure it returns responses through the shim (shim.Success/shim.Error) so the payload is a valid marshaled pb.Response.
  2. Align peer and chaincode fabric versions / protobuf definitions so the Response schema matches.
  3. Reproduce locally with the same input and log the raw resp.Payload bytes to identify the malformed sender.
  4. Update or fix any custom middleware/decoration that rewrites chaincode messages in flight.
  5. Retry the transaction; if corruption is transient (stream glitch), re-execution typically succeeds.

Example fix

// before: chaincode returning a hand-built COMPLETED message
msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: []byte("OK"), Txid: txid}
// after: return a proper marshaled pb.Response via the shim
res := &pb.Response{Status: 200, Payload: result}
payload, _ := proto.Marshal(res)
msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: payload, Txid: txid}
Defensive patterns

Strategy: try-catch

Validate before calling

// client-side: keep peer and chaincode protos in sync; verify the response decodes
var res pb.Response
if err := proto.Unmarshal(completedMsg.Payload, &res); err != nil {
    return fmt.Errorf("malformed chaincode response payload for tx %s: %w", txid, err)
}

Type guard

func isCompletedWithValidResponse(msg *pb.ChaincodeMessage) (*pb.Response, bool) {
    if msg == nil || msg.Type != pb.ChaincodeMessage_COMPLETED {
        return nil, false
    }
    res := &pb.Response{}
    if proto.Unmarshal(msg.Payload, res) != nil {
        return nil, false
    }
    return res, true
}

Try / catch

res, ccEvent, err := chaincodeSupport.Execute(txParams, ccName, input)
if err != nil {
    if strings.Contains(err.Error(), "failed to unmarshal response") {
        // malformed payload: inspect chaincode shim version/protos, then retry once
        return retryTransaction(txParams)
    }
    return err
}

Prevention

When it happens

Trigger: A chaincode sends a ChaincodeMessage_COMPLETED whose Payload bytes are empty, truncated, or not a marshaled pb.Response (e.g. chaincode code constructs the COMPLETED message manually instead of via GetReturnValue/response helpers, or a corrupted frame crossed the gRPC stream). Triggered via ChaincodeSupport.Execute or ExecuteLegacyInit -> processChaincodeExecutionResult.

Common situations: Custom chaincode shim modifications or forks that emit raw COMPLETED payloads; protobuf schema mismatches between peer and chaincode (mixed fabric versions); corrupted messages after network issues; third-party SDKs building the message by hand.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/261008fa3ae4fe25. Report an issue: GitHub.