{"record":{"id":"6198a38158bfe36b","repo":"hyperledger/fabric","slug":"transaction-d-s-does-not-match-its-raw-form","errorCode":null,"errorMessage":"transaction %d (%s) does not match its raw form (%s)","messagePattern":"transaction (.+?) \\((.+?)\\) does not match its raw form \\((.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/blockutils.go","lineNumber":350,"sourceCode":"\n\t\tif len(env.Payload) == 0 {\n\t\t\treturn fmt.Errorf(\"transaction %d has no payload\", i)\n\t\t}\n\n\t\tif len(env.Signature) == 0 {\n\t\t\treturn fmt.Errorf(\"transaction %d has no signature\", i)\n\t\t}\n\n\t\texpected, err := proto.Marshal(env)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed re-marshaling envelope: %v\", err)\n\t\t}\n\n\t\tif len(expected) < len(rawTx) {\n\t\t\treturn fmt.Errorf(\"transaction %d has %d trailing bytes\", i, len(rawTx)-len(expected))\n\t\t}\n\t\tif !bytes.Equal(expected, rawTx) {\n\t\t\treturn fmt.Errorf(\"transaction %d (%s) does not match its raw form (%s)\", i,\n\t\t\t\tbase64.StdEncoding.EncodeToString(expected), base64.StdEncoding.EncodeToString(rawTx))\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":332,"sourceCodeEnd":357,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/blockutils.go#L332-L357","documentation":"The final well-formedness check requires the re-marshaled Envelope to be byte-identical to the original raw entry. Any difference (same length, different bytes) means the entry is not a canonical serialization of the envelope it claims to be, so block hashing would be ambiguous. The error includes base64 of both forms to aid diagnosis.","triggerScenarios":"BlockDataHash finds bytes.Equal(expected, rawTx) == false at index i — the raw bytes were modified after marshaling (field reordering, altered unknown fields, in-place edits), even though they still unmarshal successfully.","commonSituations":"A peer or tool mutated envelope bytes (e.g. re-encoded with a different protobuf runtime producing different field order for the same message); deliberate tampering; copying blocks between fabric versions with changed proto definitions; naive byte-level edits of stored blocks.","solutions":["Compare the two base64 strings in the error to identify which fields differ.","Ensure the producer serialized the envelope exactly once with proto.Marshal and stored that output unmodified.","Align protobuf library/runtime versions between block producer and verifier.","Replace the block with a canonical re-marshal from a trusted source if provenance allows."],"exampleFix":"// before: editing raw bytes then storing them\nraw[10] = 0x00\nblock.Data.Data = [][]byte{raw}\n// after: modify the message, then re-marshal\nenv.Payload = newPayload\nraw, err := protoutil.Marshal(env)","handlingStrategy":"validation","validationCode":"expected, err := proto.Marshal(env)\nif err != nil { return err }\nif !bytes.Equal(expected, rawTx) {\n\treturn fmt.Errorf(\"tx %d: non-canonical serialization\", i)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat marshaled envelope bytes as immutable — modify the message, then re-marshal.","Keep protobuf runtime versions aligned between producers and verifiers.","Add round-trip equality tests (Marshal/Unmarshal/Marshal) to CI.","Verify block integrity (hashes) before processing data entries."],"tags":["hyperledger-fabric","protobuf","block-validation","integrity"],"backgroundTag":"envelope-bytes-mismatch","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"}