{"record":{"id":"ffb9d4a3d14ec3e7","repo":"hyperledger/fabric","slug":"failed-re-marshaling-envelope-v","errorCode":null,"errorMessage":"failed re-marshaling envelope: %v","messagePattern":"failed re-marshaling envelope: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/blockutils.go","lineNumber":343,"sourceCode":"\t}\n\n\tfor i, rawTx := range bd.Data {\n\t\tenv := &cb.Envelope{}\n\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":325,"sourceCodeEnd":357,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/blockutils.go#L325-L357","documentation":"During well-formedness verification the Envelope is re-marshaled with proto.Marshal(env) to compare against the original raw bytes. If proto.Marshal returns an error (e.g. an invalid required field or a marshal failure inside the payload submessage), the function surfaces it wrapped as 'failed re-marshaling envelope: %v'. This guards against envelopes that unmarshal but cannot round-trip deterministically.","triggerScenarios":"BlockDataHash iterates block data, successfully unmarshals an Envelope, but proto.Marshal(env) fails — typically due to unknown/invalid fields or a marshal error deep inside Payload/ChannelHeader submessages.","commonSituations":"Blocks produced by a different protobuf runtime version with incompatible wire data; corrupted submessages that unmarshal leniently but fail strict re-marshal; hand-edited protobuf bytes in test fixtures.","solutions":["Read the wrapped %v cause to identify which field/submessage failed to marshal.","Rebuild the envelope with the same protobuf library version (google.golang.org/protobuf) used by the rest of the network.","Re-fetch or regenerate the block from a trusted source.","If caused by unknown fields, re-marshal through a clean proto.Clone to canonicalize before hashing."],"exampleFix":"// before: mixing github.com/golang/protobuf and google.golang.org/protobuf\nimport \"github.com/golang/protobuf/proto\"\n// after\nimport \"google.golang.org/protobuf/proto\"","handlingStrategy":"try-catch","validationCode":"env := &cb.Envelope{}\nif err := proto.Unmarshal(rawTx, env); err != nil { return err }\nif _, err := proto.Marshal(env); err != nil {\n\treturn fmt.Errorf(\"envelope does not round-trip: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"defer func() {\n\tif r := recover(); r != nil {\n\t\tlog.Printf(\"block verification panicked: %v\", r)\n\t}\n}()\nif err := protoutil.VerifyTransactionsAreWellFormed(block); err != nil {\n\treturn fmt.Errorf(\"malformed block rejected: %w\", err)\n}","preventionTips":["Use one protobuf runtime (google.golang.org/protobuf) consistently across the network.","Keep .pb.go generated code in sync with the runtime version.","Round-trip test envelopes (Marshal→Unmarshal→Marshal) in CI.","Do not hand-edit serialized protobuf bytes."],"tags":["hyperledger-fabric","protobuf","serialization"],"backgroundTag":"protobuf-marshal-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"}