{"record":{"id":"f6be0803270d61f6","repo":"hyperledger/fabric","slug":"failed-to-deserialize-chaincode-action","errorCode":null,"errorMessage":"failed to deserialize chaincode action","messagePattern":"failed to deserialize chaincode action","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pkg/gateway/evaluate.go","lineNumber":169,"sourceCode":"\t\treturn \"\", \"\", false, fmt.Errorf(\"no chaincode name is provided, channel id [%s]\", channelHeader.GetChannelId())\n\t}\n\n\treturn channelHeader.GetChannelId(), spec.GetChaincodeSpec().GetChaincodeId().GetName(), len(payload.TransientMap) > 0, nil\n}\n\nfunc getResultFromProposalResponse(proposalResponse *peer.ProposalResponse) ([]byte, error) {\n\tresponsePayload := &peer.ProposalResponsePayload{}\n\tif err := proto.Unmarshal(proposalResponse.GetPayload(), responsePayload); err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to deserialize proposal response payload\")\n\t}\n\n\treturn getResultFromProposalResponsePayload(responsePayload)\n}\n\nfunc getResultFromProposalResponsePayload(responsePayload *peer.ProposalResponsePayload) ([]byte, error) {\n\tchaincodeAction := &peer.ChaincodeAction{}\n\tif err := proto.Unmarshal(responsePayload.GetExtension(), chaincodeAction); err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to deserialize chaincode action\")\n\t}\n\n\treturn chaincodeAction.GetResponse().GetPayload(), nil\n}\n","sourceCodeStart":151,"sourceCodeEnd":174,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/pkg/gateway/evaluate.go#L151-L174","documentation":"getResultFromProposalResponsePayload wraps errors from proto.Unmarshal of the ProposalResponsePayload's Extension bytes into a peer.ChaincodeAction. The Extension must contain a ChaincodeAction; failure means those bytes are invalid or of the wrong type, so the gateway cannot extract the chaincode response payload (result/return value).","triggerScenarios":"During Evaluate, the successfully unmarshaled ProposalResponsePayload's GetExtension() bytes fail to unmarshal as ChaincodeAction — e.g. corrupted extension bytes or a manually built payload with the wrong content in Extension.","commonSituations":"Replaying or mocking proposal responses where Extension was set to arbitrary bytes; payload tampering or truncation; cross-version proto incompatibility when responses were produced by an old Fabric peer.","solutions":["Get the proposal response from a genuine peer endorsement/evaluation instead of reconstructing it","Confirm Extension contains a serialized ChaincodeAction (decode with protoc to inspect)","Fetch a fresh response if the stored one may be corrupted","Align Fabric proto/SDK versions between producer and consumer"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"prp := &peer.ProposalResponsePayload{}\nif err := proto.Unmarshal(proposalResponse.GetPayload(), prp); err != nil || len(prp.GetExtension()) == 0 {\n    return fmt.Errorf(\"proposal response payload extension missing or invalid\")\n}","typeGuard":"func isParseableChaincodeAction(b []byte) bool {\n    ca := &peer.ChaincodeAction{}\n    return proto.Unmarshal(b, ca) == nil\n}","tryCatchPattern":"result, err := getResultFromProposalResponsePayload(prp)\nif err != nil {\n    log.Printf(\"chaincode action unreadable: %v\", err)\n    return nil, fmt.Errorf(\"endorsement response unusable, re-endorse: %w\", err)\n}","preventionTips":["Only consume Extension bytes produced by a genuine Fabric peer endorsement","Re-fetch responses rather than replaying cached bytes of unknown provenance","Verify peer and SDK proto versions match"],"tags":["fabric","gateway","protobuf","deserialization","chaincode-action"],"backgroundTag":"protobuf-deserialization-failed","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"}