{"record":{"id":"684ebf1479b1a86e","repo":"hyperledger/fabric","slug":"nil-payload-channel-header","errorCode":null,"errorMessage":"nil payload channel header","messagePattern":"nil payload channel header","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tx/processor_factory.go","lineNumber":78,"sourceCode":"\n\tpayload, err := protoutil.UnmarshalPayload(txenv.Payload)\n\tif err != nil {\n\t\treturn nil, &tx.InvalidErr{\n\t\t\tActualErr:      err,\n\t\t\tValidationCode: peer.TxValidationCode_BAD_PAYLOAD,\n\t\t}\n\t}\n\n\tif payload.Header == nil {\n\t\treturn nil, &tx.InvalidErr{\n\t\t\tActualErr:      errors.New(\"nil payload header\"),\n\t\t\tValidationCode: peer.TxValidationCode_BAD_PAYLOAD,\n\t\t}\n\t}\n\n\tif len(payload.Header.ChannelHeader) == 0 {\n\t\treturn nil, &tx.InvalidErr{\n\t\t\tActualErr:      errors.New(\"nil payload channel header\"),\n\t\t\tValidationCode: peer.TxValidationCode_BAD_PAYLOAD,\n\t\t}\n\t}\n\n\tchdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)\n\tif err != nil {\n\t\treturn nil, &tx.InvalidErr{\n\t\t\tActualErr:      err,\n\t\t\tValidationCode: peer.TxValidationCode_BAD_PAYLOAD,\n\t\t}\n\t}\n\n\tif len(payload.Header.SignatureHeader) == 0 {\n\t\treturn nil, &tx.InvalidErr{\n\t\t\tActualErr:      errors.New(\"nil payload signature header\"),\n\t\t\tValidationCode: peer.TxValidationCode_BAD_PAYLOAD,\n\t\t}\n\t}","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/tx/processor_factory.go#L60-L96","documentation":"After confirming payload.Header exists, validateProtoAndConstructTxEnv requires the ChannelHeader bytes to be non-empty. The ChannelHeader carries channel ID, tx type, and txid, all needed to construct a TxEnv; an empty one yields BAD_PAYLOAD. This precedes UnmarshalChannelHeader.","triggerScenarios":"payload.Header = &common.Header{SignatureHeader: shdrBytes} with ChannelHeader left unset/empty — e.g. only the signature header was marshaled into the Header.","commonSituations":"Partial header assembly where only SignatureHeader was populated; zero-value struct initialization of common.Header; clients skipping channel-header serialization steps.","solutions":["Marshal a populated ChannelHeader and assign it: Header.ChannelHeader = protoutil.Marshal(chdr).","Build headers together with protoutil.MakePayloadHeader so both sub-headers are always set.","Pre-check len(payload.Header.ChannelHeader) > 0 before sending."],"exampleFix":"// before\nhdr := &common.Header{SignatureHeader: shdrBytes}\n// after\nchdrBytes, _ := protoutil.Marshal(chdr)\nhdr := &common.Header{ChannelHeader: chdrBytes, SignatureHeader: shdrBytes}","handlingStrategy":"validation","validationCode":"if payload.Header == nil || len(payload.Header.ChannelHeader) == 0 { return errors.New(\"channel header bytes missing\") }","typeGuard":"func hasChannelHeader(p *common.Payload) bool { return p != nil && p.Header != nil && len(p.Header.ChannelHeader) > 0 }","tryCatchPattern":null,"preventionTips":["Marshal ChannelHeader and SignatureHeader together in a single header-builder helper.","Unmarshal the ChannelHeader back in unit tests to round-trip check serialization.","Never assign Header sub-fields selectively; populate both in one function."],"tags":["fabric","transaction-validation","payload"],"backgroundTag":"malformed-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"}