{"record":{"id":"4f2ecbfc7928d386","repo":"hyperledger/fabric","slug":"failed-to-extract-envelope-from-the-block","errorCode":null,"errorMessage":"failed to extract envelope from the block","messagePattern":"failed to extract envelope from the block","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":138,"sourceCode":"\t\t\tif val, ok := ordererConfigGroup.GetValues()[\"ConsensusType\"]; ok {\n\t\t\t\tif baseVersion == val.GetVersion() {\n\t\t\t\t\t// Only if the version in the write set differs from the read-set\n\t\t\t\t\t// should we consider this to be an update to the consensus type\n\t\t\t\t\treturn nil, nil, nil\n\t\t\t\t}\n\t\t\t\treturn MetadataFromConfigValue(val)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil, nil, nil\n}\n\n// ConfigChannelHeader expects a config block and returns the header type\n// of the config envelope wrapped in it, e.g. HeaderType_ORDERER_TRANSACTION\nfunc ConfigChannelHeader(block *common.Block) (hdr *common.ChannelHeader, err error) {\n\tenvelope, err := protoutil.ExtractEnvelope(block, 0)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to extract envelope from the block\")\n\t}\n\n\tchannelHeader, err := protoutil.ChannelHeader(envelope)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"cannot extract channel header\")\n\t}\n\n\treturn channelHeader, nil\n}\n\n// ConfigEnvelopeFromBlock extracts configuration envelope from the block based on the\n// config type, i.e. HeaderType_ORDERER_TRANSACTION or HeaderType_CONFIG\nfunc ConfigEnvelopeFromBlock(block *common.Block) (*common.Envelope, error) {\n\tif block == nil {\n\t\treturn nil, errors.New(\"nil block\")\n\t}\n\n\tenvelope, err := protoutil.ExtractEnvelope(block, 0)","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L120-L156","documentation":"ConfigChannelHeader extracts envelope 0 from what must be a config block and returns its channel header type. If protoutil.ExtractEnvelope fails — the block is nil/has no data, index 0 does not exist, or the payload is malformed — the error is wrapped as 'failed to extract envelope from the block'. It signals the caller (writeConfigBlock) was handed something that is not a valid config block.","triggerScenarios":"writeConfigBlock invokes ConfigChannelHeader on a block whose Data is empty or whose first envelope fails extraction/validation (bad signature header framing, truncated payload bytes).","commonSituations":"A zero or malformed block passed into the raft consensus layer during chain init; block corruption on disk; a caller mistakenly passing a regular (non-config) or partially formed block.","solutions":["Verify the block passed to writeConfigBlock is a genuine, fully formed config block (non-nil Data with at least one envelope)","Check for block corruption on disk; if the genesis block is bad, recreate/rejoin the channel","Trace the block source (file ledger / replication) for truncation and restore from a valid peer/orderer copy"],"exampleFix":"// before\nhdr, err := ConfigChannelHeader(block)\n// after\nif block == nil || block.Data == nil || len(block.Data.Data) == 0 {\n\treturn errors.New(\"invalid config block: no envelopes\")\n}\nhdr, err := ConfigChannelHeader(block)","handlingStrategy":"type-guard","validationCode":"func isWellFormedConfigBlock(block *common.Block) bool {\n\treturn block != nil && block.Header != nil && block.Data != nil &&\n\t\tlen(block.Data.Data) > 0\n}\n// use before passing to writeConfigBlock","typeGuard":"func hasEnvelopeAtIndex(block *common.Block, i uint64) bool {\n\tif block == nil || block.Data == nil {\n\t\treturn false\n\t}\n\tenvs, err := protoutil.GetEnvelopeFromBlock(block.Data.Data) \n\t_ = envs\n\treturn err == nil && len(block.Data.Data) > int(i)\n}","tryCatchPattern":"hdr, err := ConfigChannelHeader(block)\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed to extract envelope from the block\") {\n\t\treturn fmt.Errorf(\"block %d is not a valid config block — check ledger/replication source\", block.GetHeader().GetNumber())\n\t}\n\treturn err\n}","preventionTips":["Confirm block.Data has entries before feeding blocks into consensus","Verify genesis blocks are generated correctly for the channel","Watch for storage/replication truncation in ledger files","Pass only committed config blocks into writeConfigBlock paths"],"tags":["raft","block","config","envelope","validation"],"backgroundTag":"malformed-config-block","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"}