{"record":{"id":"f00583d30549270c","repo":"hyperledger/fabric","slug":"transaction-d-has-d-trailing-bytes","errorCode":null,"errorMessage":"transaction %d has %d trailing bytes","messagePattern":"transaction (.+?) has (.+?) trailing bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/blockutils.go","lineNumber":347,"sourceCode":"\t\tif err := proto.Unmarshal(rawTx, env); err != nil {\n\t\t\treturn fmt.Errorf(\"transaction %d is invalid: %v\", i, err)\n\t\t}\n\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":329,"sourceCodeEnd":357,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/blockutils.go#L329-L357","documentation":"After re-marshaling, the canonical byte length must not be shorter than the raw transaction bytes; if it is, the raw entry contains trailing bytes appended after the valid Envelope. The library rejects such data because a block entry must be exactly one serialized Envelope — trailing bytes indicate corruption or tampering.","triggerScenarios":"BlockDataHash finds len(rawTx) > len(proto.Marshal(env)) at index i, i.e. extra bytes were appended to a serialized envelope inside block.Data.Data.","commonSituations":"Manual assembly of block data concatenating multiple envelopes into one entry; padding added by a buggy serializer; corrupted storage or a malformed externally generated block; concatenating envelope bytes without splitting in a custom tool.","solutions":["Check how the block was produced — ensure each Data entry is exactly one proto.Marshal(env) result, never a concatenation.","Trim or re-serialize: extract the first envelope's bytes and discard the remainder only if you understand the provenance.","Re-fetch the block from a trusted peer/orderer.","In block-building tools, always store len(expected) bytes, not len(rawTx)."],"exampleFix":"// before: concatenating envelopes\ndata := append(env1Bytes, env2Bytes...)\n// after: one envelope per data entry\nblock.Data.Data = [][]byte{env1Bytes, env2Bytes}","handlingStrategy":"validation","validationCode":"expected, err := proto.Marshal(env)\nif err != nil { return err }\nif len(rawTx) != len(expected) {\n\treturn fmt.Errorf(\"tx %d: length mismatch (%d vs %d), trailing bytes?\", i, len(rawTx), len(expected))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Store exactly one serialized envelope per block Data entry.","Never concatenate envelope bytes into a single entry.","Slice buffers to the marshaled length before appending to block data.","Re-fetch blocks from trusted peers when validation reports trailing bytes."],"tags":["hyperledger-fabric","protobuf","block-validation"],"backgroundTag":"trailing-bytes-after-envelope","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"}