{"record":{"id":"b709e1fecfd07be4","repo":"hyperledger/fabric","slug":"inner-header-is-nil","errorCode":null,"errorMessage":"inner header is nil","messagePattern":"inner header is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/configverifier.go","lineNumber":202,"sourceCode":"\n\tif configOptions.LeaderRotation == smartbft.Options_ROTATION_ON {\n\t\treturn fmt.Errorf(\"leader rotation must be turned off for this version or be unspecified\")\n\t}\n\n\treturn nil\n}\n\nfunc (cbv *ConfigBlockValidator) verifyConfigUpdateMsg(outEnv *common.Envelope, confEnv *common.ConfigEnvelope, chdr *common.ChannelHeader) error {\n\tif confEnv == nil || confEnv.LastUpdate == nil || confEnv.Config == nil {\n\t\treturn errors.New(\"invalid config envelope\")\n\t}\n\tenvPayload, err := protoutil.UnmarshalPayload(confEnv.LastUpdate.Payload)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif envPayload.Header == nil {\n\t\treturn errors.New(\"inner header is nil\")\n\t}\n\n\tif envPayload.Header.ChannelHeader == nil {\n\t\treturn errors.New(\"inner channelheader is nil\")\n\t}\n\n\ttyp := common.HeaderType(chdr.Type)\n\n\tcbv.Logger.Infof(\"Applying filters for config update of type %s to channel %s\", typ, chdr.ChannelId)\n\n\t// First apply the filters on the outer envelope, regardless of the type of transaction it is.\n\tif err := cbv.Filters.ApplyFilters(chdr.ChannelId, outEnv); err != nil {\n\t\treturn err\n\t}\n\n\tvar expectedConfigEnv *common.ConfigEnvelope\n\tchannelID, err := protoutil.ChannelID(confEnv.LastUpdate)\n\tif err != nil {","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/configverifier.go#L184-L220","documentation":"After unmarshaling the LastUpdate envelope's payload, the verifier requires a Payload.Header. A nil header means the inner transaction payload is malformed — the channel ID and type cannot be verified — so the config update is rejected.","triggerScenarios":"confEnv.LastUpdate.Payload unmarshals but envPayload.Header == nil in verifyConfigUpdateMsg, typically because the payload was constructed without a Header.","commonSituations":"Custom-built config update transactions missing the payload header; corruption when copying an envelope from another channel; clients that marshal a Payload with only Data set.","solutions":["Populate Payload.Header with a valid common.Header (including ChannelHeader) when building the config update envelope","Build the update with SDK/tooling that constructs the full header chain instead of manual assembly","Re-fetch a known-good config update envelope and redo the modification"],"exampleFix":"// before\npayload := &common.Payload{Data: data} // Header missing\n// after\npayload := &common.Payload{Header: &common.Header{ChannelHeader: chdrBytes, SignatureHeader: shdrBytes}, Data: data}","handlingStrategy":"type-guard","validationCode":"if envPayload == nil || envPayload.Header == nil {\n    return errors.New(\"inner payload header is missing\")\n}","typeGuard":"func hasPayloadHeader(p *common.Payload) bool {\n    return p != nil && p.Header != nil\n}","tryCatchPattern":null,"preventionTips":["Always set Payload.Header when building envelopes","Use SDK builders rather than manual payload assembly","Verify unmarshaled payloads in tests before submission"],"tags":["hyperledger-fabric","smartbft","payload-header","malformed-input"],"backgroundTag":"malformed-config-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"}