hyperledger/fabric · error

missing channel header

Error message

missing channel header

What it means

BlockVerificationAssistant.UpdateConfig unmarshals a config envelope and needs its Payload.Header to read the ChannelHeader. A config transaction envelope without a header cannot be attributed to a channel, so updateConfig fails with 'missing channel header'.

Source

Thrown at common/deliverclient/block_verification.go:212

	}
	return c
}

// UpdateConfig sets the config by which blocks are verified. It is assumed that this config block had already been
// verified using the VerifyBlock method immediately prior to calling this method.
func (a *BlockVerificationAssistant) UpdateConfig(configBlock *common.Block) error {
	configTx, err := protoutil.ExtractEnvelope(configBlock, 0)
	if err != nil {
		return errors.WithMessage(err, "error extracting envelope")
	}

	payload, err := protoutil.UnmarshalPayload(configTx.Payload)
	if err != nil {
		return errors.WithMessage(err, "error unmarshalling envelope to payload")
	}

	if payload.Header == nil {
		return errors.New("missing channel header")
	}

	chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return errors.WithMessage(err, "error unmarshalling channel header")
	}

	if chdr.GetChannelId() != a.channelID {
		return errors.Errorf("config block channel ID [%s] does not match expected: [%s]", chdr.GetChannelId(), a.channelID)
	}

	configEnvelope, err := configtx.UnmarshalConfigEnvelope(payload.Data)
	if err != nil {
		return errors.WithMessage(err, "error unmarshalling config envelope from payload data")
	}

	verifierFunc, err := a.verifierAssembler.VerifierFromConfig(configEnvelope, chdr.GetChannelId())
	if err != nil {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the block is actually a CONFIG block (block.Metadata[common.BlockMetadataIndex_LAST_CONFIG] / protoutil.IsConfigBlock) before calling UpdateConfig.
  2. Unmarshal with protoutil.UnmarshalPayload/EnvelopeToPayload on the correct envelope and fix upstream envelope construction to include the header.
  3. Check ledger/block storage integrity if blocks come from persisted storage.

Example fix

// before
if err := bva.UpdateConfig(anyEnvelope); err != nil {...}

// after
if !protoutil.IsConfigBlock(block) { return errors.New("not a config block") }
payload, _ := protoutil.UnmarshalPayload(envelope.Payload)
if payload.Header == nil { return errors.New("envelope has no header") }
_ = bva.UpdateConfig(envelope)
Defensive patterns

Strategy: validation

Validate before calling

payload, err := protoutil.UnmarshalPayload(configTx.Payload)
if err != nil { return err }
if payload.Header == nil { return errors.New("config envelope has no header") }

Type guard

func isUsableConfigEnvelope(env *common.Envelope) bool {
    p, err := protoutil.UnmarshalPayload(env.Payload)
    return err == nil && p != nil && p.Header != nil && p.Header.ChannelHeader != nil
}

Try / catch

if err := bva.UpdateConfig(env); err != nil {
    if strings.Contains(err.Error(), "missing channel header") {
        // re-read the block from the ledger; storage may be corrupt
    }
    return err
}

Prevention

When it happens

Trigger: UpdateConfig is fed a config envelope whose inner payload has Header unset — e.g. the caller passed a data-carrying envelope, a config tx produced without protoutil envelope helpers, or a corrupted payload.

Common situations: Custom deliver clients that extract config blocks and feed them to the assistant but mis-parse the envelope; corrupted block storage; feeding a non-config transaction envelope into UpdateConfig.

Related errors


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