{"record":{"id":"6748bb802b68effa","repo":"hyperledger/fabric","slug":"missing-channel-header","errorCode":null,"errorMessage":"missing channel header","messagePattern":"missing channel header","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/deliverclient/block_verification.go","lineNumber":212,"sourceCode":"\t}\n\treturn c\n}\n\n// UpdateConfig sets the config by which blocks are verified. It is assumed that this config block had already been\n// verified using the VerifyBlock method immediately prior to calling this method.\nfunc (a *BlockVerificationAssistant) UpdateConfig(configBlock *common.Block) error {\n\tconfigTx, err := protoutil.ExtractEnvelope(configBlock, 0)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"error extracting envelope\")\n\t}\n\n\tpayload, err := protoutil.UnmarshalPayload(configTx.Payload)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"error unmarshalling envelope to payload\")\n\t}\n\n\tif payload.Header == nil {\n\t\treturn errors.New(\"missing channel header\")\n\t}\n\n\tchdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"error unmarshalling channel header\")\n\t}\n\n\tif chdr.GetChannelId() != a.channelID {\n\t\treturn errors.Errorf(\"config block channel ID [%s] does not match expected: [%s]\", chdr.GetChannelId(), a.channelID)\n\t}\n\n\tconfigEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"error unmarshalling config envelope from payload data\")\n\t}\n\n\tverifierFunc, err := a.verifierAssembler.VerifierFromConfig(configEnvelope, chdr.GetChannelId())\n\tif err != nil {","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/deliverclient/block_verification.go#L194-L230","documentation":"BlockVerificationAssistant.UpdateConfig unmarshals a config envelope and needs its Payload.Header to read the ChannelHeader. A config transaction envelope without a header cannot be attributed to a channel, so updateConfig fails with 'missing channel header'.","triggerScenarios":"UpdateConfig is fed a config envelope whose inner payload has Header unset — e.g. the caller passed a data-carrying envelope, a config tx produced without protoutil envelope helpers, or a corrupted payload.","commonSituations":"Custom deliver clients that extract config blocks and feed them to the assistant but mis-parse the envelope; corrupted block storage; feeding a non-config transaction envelope into UpdateConfig.","solutions":["Verify the block is actually a CONFIG block (block.Metadata[common.BlockMetadataIndex_LAST_CONFIG] / protoutil.IsConfigBlock) before calling UpdateConfig.","Unmarshal with protoutil.UnmarshalPayload/EnvelopeToPayload on the correct envelope and fix upstream envelope construction to include the header.","Check ledger/block storage integrity if blocks come from persisted storage."],"exampleFix":"// before\nif err := bva.UpdateConfig(anyEnvelope); err != nil {...}\n\n// after\nif !protoutil.IsConfigBlock(block) { return errors.New(\"not a config block\") }\npayload, _ := protoutil.UnmarshalPayload(envelope.Payload)\nif payload.Header == nil { return errors.New(\"envelope has no header\") }\n_ = bva.UpdateConfig(envelope)","handlingStrategy":"validation","validationCode":"payload, err := protoutil.UnmarshalPayload(configTx.Payload)\nif err != nil { return err }\nif payload.Header == nil { return errors.New(\"config envelope has no header\") }","typeGuard":"func isUsableConfigEnvelope(env *common.Envelope) bool {\n    p, err := protoutil.UnmarshalPayload(env.Payload)\n    return err == nil && p != nil && p.Header != nil && p.Header.ChannelHeader != nil\n}","tryCatchPattern":"if err := bva.UpdateConfig(env); err != nil {\n    if strings.Contains(err.Error(), \"missing channel header\") {\n        // re-read the block from the ledger; storage may be corrupt\n    }\n    return err\n}","preventionTips":["Only feed protoutil.IsConfigBlock-confirmed blocks to UpdateConfig","Use SDK/configtx helpers to produce config envelopes with complete headers","Check block storage integrity if blocks come from persisted files"],"tags":["hyperledger-fabric","deliver-client","config-block","malformed-envelope"],"backgroundTag":"missing-required-header","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"}