hyperledger/fabric · error

no header was set

Error message

no header was set

What it means

ConfigBlockValidator.ValidateConfig in orderer/consensus/smartbft/configverifier.go:70 returns "no header was set" when the payload inside a config envelope has a nil Header field. After protoutil.UnmarshalPayload succeeds, the validator requires payload.Header (a common.Header) to be present before it can inspect the channel header. A headerless payload cannot be attributed to a channel or typed, so config validation fails immediately.

Source

Thrown at orderer/consensus/smartbft/configverifier.go:70

}

// ConfigBlockValidator struct
type ConfigBlockValidator struct {
	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)

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Rebuild the envelope ensuring a common.Header is populated (ChannelHeader + SignatureHeader) before marshaling the payload.
  2. Use protoutil.CreateSignedEnvelope / protoutil.MarshalOrPanic helpers so Header is always set.
  3. Inspect the source block/transaction to confirm it was not corrupted; re-fetch or re-submit from a valid source.
  4. Verify the client SDK version builds payloads with headers (channel header type set to CONFIG for config txs).

Example fix

// before
payload := &common.Payload{Data: configBytes}
// after
chdr := &common.ChannelHeader{Type: int32(common.HeaderType_CONFIG), ChannelId: "mychannel"}
sighdr := &common.SignatureHeader{Creator: creatorBytes, Nonce: nonce}
payload := &common.Payload{
    Header: &common.Header{ChannelHeader: protoutil.MarshalOrPanic(chdr), SignatureHeader: protoutil.MarshalOrPanic(sighdr)},
    Data:   configBytes,
}
Defensive patterns

Strategy: validation

Validate before calling

payload, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil {
    return fmt.Errorf("bad payload: %w", err)
}
if payload == nil || payload.Header == nil {
    return errors.New("refusing to submit: payload has no header")
}

Type guard

func hasPayloadHeader(payload *common.Payload) bool {
    return payload != nil && payload.Header != nil
}

Try / catch

if err := cbv.ValidateConfig(envelope); err != nil {
    if strings.Contains(err.Error(), "no header was set") {
        return fmt.Errorf("malformed config envelope: rebuild with protoutil.CreateSignedEnvelope")
    }
    return err
}

Prevention

When it happens

Trigger: ValidateConfig is called with an envelope whose Payload marshals successfully but carries Header == nil — e.g. an envelope constructed manually with only Payload.Data set, or a payload whose Header bytes were empty/omitted during marshaling.

Common situations: Hand-crafted envelopes in tests or tools that set Payload without Header; corrupted or truncated blocks read from the ledger; a custom client/SDK that builds common.Payload without populating Header; protobuf marshaling with empty-message omission producing a nil header on decode.

Related errors


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