{"record":{"id":"b72a01bea6ea1ecc","repo":"hyperledger/fabric","slug":"empty-header-extension","errorCode":null,"errorMessage":"empty header extension","messagePattern":"empty header extension","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tx/endorser/parser.go","lineNumber":44,"sourceCode":"// EndorserTx represents a parsed common.Envelope protobuf\ntype EndorserTx struct {\n\tComputedTxID string\n\tChannelID    string\n\tChaincodeID  *peer.ChaincodeID\n\tCreator      []byte\n\tResponse     *peer.Response\n\tEvents       []byte\n\tResults      []byte\n\tEndorsements []*peer.Endorsement\n\tType         int32\n\tVersion      int32\n\tEpoch        uint64\n\tNonce        []byte\n}\n\nfunc unmarshalEndorserTx(txenv *tx.Envelope) (*EndorserTx, error) {\n\tif len(txenv.ChannelHeader.Extension) == 0 {\n\t\treturn nil, errors.New(\"empty header extension\")\n\t}\n\n\thdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(\n\t\ttxenv.ChannelHeader.Extension,\n\t)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(txenv.Data) == 0 {\n\t\treturn nil, errors.New(\"nil payload data\")\n\t}\n\n\ttx, err := protoutil.UnmarshalTransaction(txenv.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/tx/endorser/parser.go#L26-L62","documentation":"unmarshalEndorserTx parses a transaction envelope's channel header extension to extract chaincode header extension data (chaincode ID, etc.). If txenv.ChannelHeader.Extension is empty there is nothing to parse, so this error is thrown before attempting unmarshalling.","triggerScenarios":"Calling UnmarshalEndorserTxAndValidate with an envelope whose ChannelHeader has no Extension bytes — e.g. a config or non-endorser transaction passed to an endorser-transaction parser.","commonSituations":"Passing a chaincode config-update or non-endorser envelope to the parser; envelope built incorrectly by client SDK; wrong transaction type routed to endorser validation.","solutions":["Ensure the envelope being parsed is an endorser transaction (type ENDORSER_TRANSACTION) with a populated ChannelHeader.Extension","Fix client SDK payload construction to include the ChaincodeHeaderExtension","Check the transaction type before calling UnmarshalEndorserTxAndValidate"],"exampleFix":"// before\nprotoutil.UnmarshalChaincodeHeaderExtension(txenv.ChannelHeader.Extension) // panics/errors on empty\n// after\nif txenv.ChannelHeader != nil && len(txenv.ChannelHeader.Extension) == 0 {\n    return nil, errors.New(\"empty header extension\")\n}","handlingStrategy":"validation","validationCode":"// before parsing, check transaction type and extension presence\nif ch, _ := txEnvelope.GetChannelHeader(); ch == nil || len(ch.Extension) == 0 {\n    return errors.New(\"envelope lacks channel header extension\")\n}","typeGuard":"func hasChannelHeaderExtension(env *common.Envelope) bool {\n    ch, err := protoutil.ChannelHeader(env.Payload)\n    return err == nil && ch != nil && len(ch.Extension) > 0\n}","tryCatchPattern":"tx, err := tx.UnmarshalEndorserTxAndValidate(env)\nif err != nil {\n    if strings.Contains(err.Error(), \"empty header extension\") {\n        // not an endorser tx: skip or route to correct parser\n    }\n    return err\n}","preventionTips":["Verify transaction type is ENDORSER_TRANSACTION before parsing","Ensure SDKs populate ChaincodeHeaderExtension in channel header","Reject envelopes missing channel header early in ingestion","Keep protoutil/protobuf versions consistent"],"tags":["fabric","tx-parser","endorser","validation"],"backgroundTag":"empty-header-extension","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"}