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

  1. Populate common.Header.ChannelHeader with a marshaled ChannelHeader (Type=HeaderType_CONFIG, ChannelId, TxId) before submitting.
  2. Prefer protoutil.CreateSignedEnvelope which always sets the channel header.
  3. Check the block/transaction source for corruption and re-obtain from a trusted peer/orderer.
  4. 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

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


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