hyperledger/fabric · error

unexpected header type: %v

Error message

unexpected header type: %v

What it means

If the block's channel header type is neither HeaderType_ORDERER_TRANSACTION nor HeaderType_CONFIG, ConfigEnvelopeFromBlock returns this error. It means the block passed in is not a configuration-related envelope — e.g. a regular transaction, peer-chaincode invocation, or config-update envelope was supplied where a config envelope was required.

Source

Thrown at orderer/consensus/etcdraft/util.go:172

	}

	envelope, err := protoutil.ExtractEnvelope(block, 0)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to extract envelope from the block")
	}

	channelHeader, err := protoutil.ChannelHeader(envelope)
	if err != nil {
		return nil, errors.Wrap(err, "cannot extract channel header")
	}

	switch channelHeader.GetType() {
	case int32(common.HeaderType_ORDERER_TRANSACTION):
		return nil, errors.Errorf("unsupported legacy system channel header type: %v", channelHeader.GetType())
	case int32(common.HeaderType_CONFIG):
		return envelope, nil
	default:
		return nil, errors.Errorf("unexpected header type: %v", channelHeader.GetType())
	}
}

// ConsensusMetadataFromConfigBlock reads consensus metadata updates from the configuration block
func ConsensusMetadataFromConfigBlock(block *common.Block) (*etcdraft.ConfigMetadata, *orderer.ConsensusType, error) {
	if block == nil {
		return nil, nil, errors.New("nil block")
	}

	if !protoutil.IsConfigBlock(block) {
		return nil, nil, errors.New("not a config block")
	}

	configEnvelope, err := ConfigEnvelopeFromBlock(block)
	if err != nil {
		return nil, nil, errors.Wrap(err, "cannot read config update")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Guard the call with protoutil.IsConfigBlock(block) (as ConsensusMetadataFromConfigBlock does) before parsing.
  2. Locate the latest config block via the ledger's config manager (or the block whose header type is HeaderType_CONFIG) and pass that one.
  3. Check channelHeader.Type before invoking to give a clearer failure message.

Example fix

// before
block, _ := ledger.GetBlockByNumber(currentHeight - 1)
meta, _, err := ConsensusMetadataFromConfigBlock(block) // may be a tx block

// after
block, _ := ledger.GetBlockByNumber(currentHeight - 1)
if !protoutil.IsConfigBlock(block) {
    return errors.New("expected config block, got regular block")
}
meta, _, err := ConsensusMetadataFromConfigBlock(block)
Defensive patterns

Strategy: validation

Validate before calling

hdr, err := ConfigChannelHeader(block)
if err != nil {
    return err
}
if hdr.GetType() != int32(common.HeaderType_CONFIG) {
    return errors.Errorf("block type %d is not a config block", hdr.GetType())
}

Type guard

func isConfigTypedBlock(block *common.Block) bool {
    hdr, err := ConfigChannelHeader(block)
    return err == nil && hdr.GetType() == int32(common.HeaderType_CONFIG)
}

Try / catch

envelope, err := ConfigEnvelopeFromBlock(block)
if err != nil {
    if strings.Contains(err.Error(), "unexpected header type") {
        logger.Warnf("skipping non-config block %d", block.Header.Number)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling ConsensusMetadataFromConfigBlock with a non-config block (HeaderType_TRANSACTION/ENDORSER_TRANSACTION etc.), typically because a normal application block was mistaken for a config block.

Common situations: Subscribing to block events and forwarding every block to config parsing without checking IsConfigBlock; passing the wrong block number (a tx block) during channel onboarding or raft metadata inspection.

Related errors


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