hyperledger/fabric · error

bad header

Error message

bad header

What it means

After the payload unmarshals, ValidateUpdateConfigEnvelope requires payload.Header and payload.Header.ChannelHeader to be present. This error is returned when either is nil, meaning the envelope lacks the metadata needed to identify the channel and message type.

Source

Thrown at orderer/common/channelparticipation/validator.go:80

		return "", errors.New("invalid config: must contain application config")
	}

	return channelID, err
}

// ValidateUpdateConfigEnvelope checks whether this envelope can be used as an update config for the channel participation API.
// It returns the channel ID.
// It verifies that it is not a system channel by checking that consortiums config does not exist.
// It verifies it is an application channel by checking that the application group exists.
// It returns an error when it cannot be used as a update config envelope.
func ValidateUpdateConfigEnvelope(env *cb.Envelope) (channelID string, err error) {
	payload, err := protoutil.UnmarshalPayload(env.Payload)
	if err != nil {
		return "", errors.New("bad payload")
	}

	if payload.Header == nil || payload.Header.ChannelHeader == nil {
		return "", errors.New("bad header")
	}

	ch, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return "", errors.New("could not unmarshall channel header")
	}

	if ch.Type != int32(cb.HeaderType_CONFIG_UPDATE) {
		return "", errors.New("bad type")
	}

	if ch.ChannelId == "" {
		return "", errors.New("empty channel id")
	}

	configUpdateEnv, err := protoutil.EnvelopeToConfigUpdate(env)
	if err != nil {
		return "", err

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Build the header with protoutil.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, version, channelID, epoch) and attach it via protoutil.MakePayloadHeader before marshaling the payload.
  2. Verify with 'configtxlator' or a small Go snippet that payload.Header.ChannelHeader is non-nil and decodable.
  3. Use an SDK or fabric CLI code path (e.g. channel update flow) that populates headers automatically instead of hand-crafting envelopes.
  4. Re-generate the config update from the current channel config rather than reusing a stripped-down envelope.

Example fix

// before
payload := &cb.Payload{Data: data} // no header
// after
chHdr := protoutil.MakeChannelHeader(cb.HeaderType_CONFIG_UPDATE, int32(1), "mychannel", 0)
payload := &cb.Payload{Header: protoutil.MakePayloadHeader(chHdr, sigHdr), Data: data}
Defensive patterns

Strategy: validation

Validate before calling

p, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil { return err }
if p.Header == nil || p.Header.ChannelHeader == nil {
    return errors.New("payload must carry a ChannelHeader")
}

Type guard

func hasChannelHeader(env *cb.Envelope) bool {
    p, err := protoutil.UnmarshalPayload(env.Payload)
    if err != nil || p.Header == nil { return false }
    return p.Header.ChannelHeader != nil
}

Try / catch

if _, err := ValidateUpdateConfigEnvelope(env); err != nil && strings.Contains(err.Error(), "bad header") {
    // rebuild payload with protoutil.MakePayloadHeader
}

Prevention

When it happens

Trigger: Submitting a config-update envelope constructed without a ChannelHeader (or with no Header at all) to the channel participation update endpoint.

Common situations: Hand-built envelopes missing the Header field; SDK calls that set Data but skip channel headers; copy-pasted envelope-construction code that populates only Payload.Data.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/0e21702ceddcc6bb. Report an issue: GitHub.