hyperledger/fabric · error
no channel header was set
Error message
no channel header was set
What it means
ValidateConfig in orderer/consensus/smartbft/configverifier.go:74 returns "no channel header was set" when payload.Header exists but its ChannelHeader field is nil. The channel header carries the channel ID and envelope type; without it the validator cannot determine whether this is a CONFIG envelope or which channel it targets. This is the second of the three structural checks on the payload header.
Source
Thrown at orderer/consensus/smartbft/configverifier.go:74
ConfigUpdateProposer ConfigUpdateProposer
ValidatingChannel string
Filters Filters
Logger *flogging.FabricLogger
}
// ValidateConfig validates config from envelope
func (cbv *ConfigBlockValidator) ValidateConfig(envelope *common.Envelope) error {
payload, err := protoutil.UnmarshalPayload(envelope.Payload)
if err != nil {
return err
}
if payload.Header == nil {
return fmt.Errorf("no header was set")
}
if payload.Header.ChannelHeader == nil {
return fmt.Errorf("no channel header was set")
}
chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
if err != nil {
return fmt.Errorf("channel header unmarshalling error: %s", err)
}
switch chdr.Type {
case int32(common.HeaderType_CONFIG):
configEnvelope := &common.ConfigEnvelope{}
if err = proto.Unmarshal(payload.Data, configEnvelope); err != nil {
return fmt.Errorf("data unmarshalling error: %s", err)
}
return cbv.verifyConfigUpdateMsg(envelope, configEnvelope, chdr)
default:
return errors.Errorf("unexpected envelope type %s", common.HeaderType_name[chdr.Type])
}
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Populate common.Header.ChannelHeader with a marshaled ChannelHeader (Type=HeaderType_CONFIG, ChannelId, TxId) before submitting.
- Prefer protoutil.CreateSignedEnvelope which always sets the channel header.
- Check the block/transaction source for corruption and re-obtain from a trusted peer/orderer.
- Add client-side validation that header.ChannelHeader != nil before broadcasting the envelope.
Example fix
// before
hdr := &common.Header{SignatureHeader: sighdrBytes}
// after
hdr := &common.Header{
ChannelHeader: protoutil.MarshalOrPanic(&common.ChannelHeader{Type: int32(common.HeaderType_CONFIG), ChannelId: "mychannel"}),
SignatureHeader: sighdrBytes,
} Defensive patterns
Strategy: type-guard
Validate before calling
if payload.Header == nil || payload.Header.ChannelHeader == nil {
return errors.New("envelope missing channel header; cannot submit config transaction")
} Type guard
func hasChannelHeader(h *common.Header) bool {
return h != nil && h.ChannelHeader != nil
} Try / catch
if err := cbv.ValidateConfig(envelope); err != nil {
if strings.Contains(err.Error(), "no channel header was set") {
return fmt.Errorf("payload header lacks ChannelHeader: regenerate envelope")
}
return err
} Prevention
- Set both ChannelHeader (type, channel ID) and SignatureHeader on every common.Header.
- Use protoutil.CreateSignedEnvelope rather than assembling Header fields piecemeal.
- Add a pre-submission assertion that header.ChannelHeader != nil in custom tooling.
- Watch for proto marshal options that omit empty fields when embedding header bytes.
When it happens
Trigger: An envelope's payload has a Header populated with (at most) a SignatureHeader but ChannelHeader == nil, reaching ValidateConfig — typically from a malformed config envelope submitted to the SmartBFT ordering node.
Common situations: Tools or tests constructing common.Header with only SignatureHeader set; a serialization bug dropping the ChannelHeader bytes; corrupted ledger data; custom broadcast clients that forget to set ChannelHeader for CONFIG transactions.
Related errors
- no header was set
- channel header unmarshalling error: %s
- data unmarshalling error: %s
- malformed org definition for org: %s
- error encode input
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/ac5cfda344b8905e.
Report an issue: GitHub.