hyperledger/fabric · error
inner header is nil
Error message
inner header is nil
What it means
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.
Source
Thrown at orderer/consensus/smartbft/configverifier.go:202
if configOptions.LeaderRotation == smartbft.Options_ROTATION_ON {
return fmt.Errorf("leader rotation must be turned off for this version or be unspecified")
}
return nil
}
func (cbv *ConfigBlockValidator) verifyConfigUpdateMsg(outEnv *common.Envelope, confEnv *common.ConfigEnvelope, chdr *common.ChannelHeader) error {
if confEnv == nil || confEnv.LastUpdate == nil || confEnv.Config == nil {
return errors.New("invalid config envelope")
}
envPayload, err := protoutil.UnmarshalPayload(confEnv.LastUpdate.Payload)
if err != nil {
return err
}
if envPayload.Header == nil {
return errors.New("inner header is nil")
}
if envPayload.Header.ChannelHeader == nil {
return errors.New("inner channelheader is nil")
}
typ := common.HeaderType(chdr.Type)
cbv.Logger.Infof("Applying filters for config update of type %s to channel %s", typ, chdr.ChannelId)
// First apply the filters on the outer envelope, regardless of the type of transaction it is.
if err := cbv.Filters.ApplyFilters(chdr.ChannelId, outEnv); err != nil {
return err
}
var expectedConfigEnv *common.ConfigEnvelope
channelID, err := protoutil.ChannelID(confEnv.LastUpdate)
if err != nil {View on GitHub (pinned to 2736b63f8f)
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
Example fix
// before
payload := &common.Payload{Data: data} // Header missing
// after
payload := &common.Payload{Header: &common.Header{ChannelHeader: chdrBytes, SignatureHeader: shdrBytes}, Data: data} Defensive patterns
Strategy: type-guard
Validate before calling
if envPayload == nil || envPayload.Header == nil {
return errors.New("inner payload header is missing")
} Type guard
func hasPayloadHeader(p *common.Payload) bool {
return p != nil && p.Header != nil
} Prevention
- Always set Payload.Header when building envelopes
- Use SDK builders rather than manual payload assembly
- Verify unmarshaled payloads in tests before submission
When it happens
Trigger: confEnv.LastUpdate.Payload unmarshals but envPayload.Header == nil in verifyConfigUpdateMsg, typically because the payload was constructed without a Header.
Common situations: 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.
Related errors
- invalid config envelope
- inner channelheader is nil
- error extracting channel ID from config update
- consenter options type mismatch
- channel header not found in the envelope
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/b709e1fecfd07be4.
Report an issue: GitHub.