{"record":{"id":"3e4330917195c3b7","repo":"hyperledger/fabric","slug":"channel-header-unmarshalling-error-s","errorCode":null,"errorMessage":"channel header unmarshalling error: %s","messagePattern":"channel header unmarshalling error: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/configverifier.go","lineNumber":79,"sourceCode":"\n// ValidateConfig validates config from envelope\nfunc (cbv *ConfigBlockValidator) ValidateConfig(envelope *common.Envelope) error {\n\tpayload, err := protoutil.UnmarshalPayload(envelope.Payload)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif payload.Header == nil {\n\t\treturn fmt.Errorf(\"no header was set\")\n\t}\n\n\tif payload.Header.ChannelHeader == nil {\n\t\treturn fmt.Errorf(\"no channel header was set\")\n\t}\n\n\tchdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"channel header unmarshalling error: %s\", err)\n\t}\n\n\tswitch chdr.Type {\n\tcase int32(common.HeaderType_CONFIG):\n\t\tconfigEnvelope := &common.ConfigEnvelope{}\n\t\tif err = proto.Unmarshal(payload.Data, configEnvelope); err != nil {\n\t\t\treturn fmt.Errorf(\"data unmarshalling error: %s\", err)\n\t\t}\n\t\treturn cbv.verifyConfigUpdateMsg(envelope, configEnvelope, chdr)\n\tdefault:\n\t\treturn errors.Errorf(\"unexpected envelope type %s\", common.HeaderType_name[chdr.Type])\n\t}\n}\n\nfunc (cbv *ConfigBlockValidator) checkConsentersMatchPolicy(conf *common.Config) error {\n\tif conf == nil {\n\t\treturn fmt.Errorf(\"empty Config\")\n\t}","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/configverifier.go#L61-L97","documentation":"ValidateConfig in orderer/consensus/smartbft/configverifier.go:79 returns \"channel header unmarshalling error: %s\" when protoutil.UnmarshalChannelHeader fails to decode payload.Header.ChannelHeader bytes into a common.ChannelHeader. The ChannelHeader field is non-nil but its bytes are not a valid protobuf ChannelHeader, so the validator aborts before switching on the envelope type.","triggerScenarios":"An envelope whose Header.ChannelHeader contains bytes that fail proto.Unmarshal as common.ChannelHeader — e.g. random/garbage bytes, bytes from a different message type (SignatureHeader marshaled into the ChannelHeader slot), or truncation.","commonSituations":"Manual envelope assembly in tests/tools that marshals the wrong message into the ChannelHeader field; corrupted or tampered blocks; double-marshaling bugs in custom clients; version mismatch where a client serializes headers in an incompatible layout.","solutions":["Ensure ChannelHeader is marshaled with proto.Marshal(&common.ChannelHeader{...}) (or protoutil.MarshalOrPanic), not with another message type's bytes.","Verify the block/envelope was not truncated or corrupted; re-fetch from a healthy orderer.","Use protoutil.CreateSignedEnvelope instead of manual payload construction.","Confirm client and orderer use compatible fabric-protos versions (fabric-protos-go vs fabric-protos-go-apiv2 produce identical wire format, but hand-rolled structs may not)."],"exampleFix":"// before: wrong message marshaled into the header slot\nhdr := &common.Header{ChannelHeader: sighdrBytes} // SignatureHeader bytes\n// after\nhdr := &common.Header{\n    ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{\n        Type: int32(common.HeaderType_CONFIG), ChannelId: \"mychannel\", Epoch: 0,\n    }),\n}","handlingStrategy":"validation","validationCode":"chdr := &common.ChannelHeader{}\nif err := proto.Unmarshal(payload.Header.ChannelHeader, chdr); err != nil {\n    return fmt.Errorf(\"client-side check: channel header bytes are not a valid ChannelHeader: %w\", err)\n}\nif chdr.ChannelId == \"\" {\n    return errors.New(\"channel header has empty channel id\")\n}","typeGuard":"func isWellFormedChannelHeader(b []byte) (*common.ChannelHeader, bool) {\n    ch := &common.ChannelHeader{}\n    if err := proto.Unmarshal(b, ch); err != nil || ch.ChannelId == \"\" {\n        return nil, false\n    }\n    return ch, true\n}","tryCatchPattern":"if err := cbv.ValidateConfig(envelope); err != nil {\n    if strings.Contains(err.Error(), \"channel header unmarshalling error\") {\n        return fmt.Errorf(\"ChannelHeader bytes corrupt: re-marshal a common.ChannelHeader\")\n    }\n    return err\n}","preventionTips":["Marshal ChannelHeader with protoutil.MarshalOrPanic(&common.ChannelHeader{...}); never paste other messages' bytes into the slot.","Prefer protoutil.CreateSignedEnvelope to manual marshaling.","Verify block hashes/integrity when envelopes originate from ledger data.","Pin fabric-protos-go-apiv2 versions consistently across client and orderer."],"tags":["hyperledger-fabric","ordering","protobuf","deserialization"],"backgroundTag":"protobuf-unmarshal-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"}