hyperledger/fabric · error
failed getting a new bundle from envelope of config block
Error message
failed getting a new bundle from envelope of config block
What it means
In smartbft's remoteNodesFromConfigBlock, the genesis/config block's first envelope is unmarshalled into a cb.Envelope and then passed to channelconfig.NewBundleFromEnvelope, which validates the channel configuration and builds a config bundle. This error is a wrap of the underlying NewBundleFromEnvelope failure, meaning the config envelope is not valid channel configuration (bad payload, missing Channel header, or invalid ConfigGroup structure). It aborts building the SmartBFT cluster metadata after a config block commit.
Source
Thrown at orderer/consensus/smartbft/util.go:289
return nil, errors.WithMessage(err, "error unmarshalling channel header")
}
return &request{
chHdr: chdr,
sigHdr: sigHdr,
envelope: envelope,
}, nil
}
// remoteNodesFromConfigBlock unmarshalls the node config from the block metadata
func remoteNodesFromConfigBlock(block *cb.Block, logger *flogging.FabricLogger, bccsp bccsp.BCCSP) (*nodeConfig, error) {
env := &cb.Envelope{}
if err := proto.Unmarshal(block.Data.Data[0], env); err != nil {
return nil, errors.Wrap(err, "failed unmarshalling envelope of config block")
}
bundle, err := channelconfig.NewBundleFromEnvelope(env, bccsp)
if err != nil {
return nil, errors.Wrap(err, "failed getting a new bundle from envelope of config block")
}
channelMSPs, err := bundle.MSPManager().GetMSPs()
if err != nil {
return nil, errors.Wrap(err, "failed obtaining MSPs from MSPManager")
}
oc, ok := bundle.OrdererConfig()
if !ok {
return nil, errors.New("no orderer config in config block")
}
_, err = createSmartBftConfig(oc)
if err != nil {
return nil, err
}
var nodeIDs []uint64View on GitHub (pinned to 2736b63f8f)
Solutions
- Inspect the underlying wrapped error in the log to identify whether unmarshalling, payload extraction, or config validation failed
- Verify the block's first envelope is a config transaction (Header type = CONFIG) using protoutil.EnvelopeToPayload / configtx filter
- Regenerate the config block with configtxgen/configtxlator matching your Fabric version instead of manually editing it
- Check that all peer/orderer binaries and channel config version are compatible (config schema changes between releases)
- If block storage is suspect, repair the node by re-fetching the channel genesis/config block from a healthy orderer or re-join the channel
Example fix
// before: committing a block with a non-config envelope at index 0
block.Data.Data[0] = normalTxEnvelopeBytes
// after: ensure index 0 is the CONFIG envelope (e.g. re-created via configtxgen/configtxlator)
configEnv := protoutil.MarshalOrPanic(&cb.Envelope{Payload: configPayloadBytes})
block.Data.Data = [][]byte{configEnv} Defensive patterns
Strategy: validation
Validate before calling
env := &cb.Envelope{}
if err := proto.Unmarshal(block.Data.Data[0], env); err != nil {
return fmt.Errorf("block %d: first envelope not unmarshallable: %w", block.Header.Number, err)
}
payload, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil {
return fmt.Errorf("envelope payload invalid: %w", err)
}
chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil || chdr.Type != int32(cb.HeaderType_CONFIG) {
return fmt.Errorf("first envelope is not a CONFIG transaction (type=%d)", chdr.Type)
}
// only then call into consensus / configBlockCommitted Type guard
func isConfigBlock(block *cb.Block) bool {
if block == nil || len(block.Data.Data) == 0 {
return false
}
env := &cb.Envelope{}
if proto.Unmarshal(block.Data.Data[0], env) != nil {
return false
}
payload, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil || payload.Header == nil {
return false
}
chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
return err == nil && chdr.Type == int32(cb.HeaderType_CONFIG)
} Try / catch
block, err := ledger.GetConfigBlock()
if err != nil {
return fmt.Errorf("cannot read config block: %w", err)
}
if !isConfigBlock(block) {
return errors.New("retrieved block is not a valid config block; regenerate genesis block via configtxgen")
} Prevention
- Always generate genesis/config blocks with configtxgen for the matching Fabric version; never hand-edit block bytes
- After configtxlator round-trips, recompute and validate the envelope before committing
- Log the channelID and block number in configBlockCommitted paths to catch wrong-channel blocks early
- Verify block storage integrity (fileLedger) when nodes are cloned or restored from snapshots
When it happens
Trigger: configBlockCommitted -> remoteNodesFromConfigBlock with a block whose Data.Data[0] is an envelope that fails channelconfig.NewBundleFromEnvelope: config envelope not extractable, payload type not CONFIG, ConfigGroup missing Channel/Orderer groups, or malformed nested config values.
Common situations: Hand-crafting or mutating a config block (e.g. via configtxlator round-trips gone wrong); committing a block whose first envelope is not a config transaction (e.g. a normal tx at index 0); corrupted block storage; blocks produced by a different Fabric version with incompatible config schemas.
Related errors
- no orderer section in config block
- nil block
- failed extracting bundle from envelope
- failed to unmarshal BFT metadata configuration
- invalid BFT metadata configuration
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/82a0839de6ad73b2.
Report an issue: GitHub.