hyperledger/fabric · error

could not read config update

Error message

could not read config update

What it means

ConsensusMetadataFromConfigBlock extracts the config update from a decoded config envelope payload via configtx.UnmarshalConfigUpdateFromPayload. This wrapped error means that payload could not be parsed into a ConfigUpdate proto, so Raft consensus metadata cannot be derived from the block. It is a wrapping of the underlying parse error from pkg/errors.Wrap.

Source

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

	}

	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")
	}

	payload, err := protoutil.UnmarshalPayload(configEnvelope.GetPayload())
	if err != nil {
		return nil, nil, errors.Wrap(err, "failed to extract payload from config envelope")
	}
	// get config update
	configUpdate, err := configtx.UnmarshalConfigUpdateFromPayload(payload)
	if err != nil {
		return nil, nil, errors.Wrap(err, "could not read config update")
	}

	return MetadataFromConfigUpdate(configUpdate)
}

// VerifyConfigMetadata validates Raft config metadata.
// Note: ignores certificates expiration.
func VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts x509.VerifyOptions) error {
	if metadata == nil {
		// defensive check. this should not happen as CheckConfigMetadata
		// should always be called with non-nil config metadata
		return errors.Errorf("nil Raft config metadata")
	}

	if metadata.GetOptions() == nil {
		return errors.Errorf("nil Raft config metadata options")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect errors.Wrap'd message chain (use %+v) to see the root parse error from UnmarshalConfigUpdateFromPayload.
  2. Verify the block is actually a config block (e.g. envelope last position / header type CONFIG) before passing it in.
  3. Re-fetch the latest config block from the ordering service or peer (configtxlator/peer channel fetch config).
  4. If corruption is suspected, restore the block store from backup or resync from other orderers.

Example fix

// before: passing any block blindly
meta, err := ConsensusMetadataFromConfigBlock(anyBlock)
// after: only pass verified config blocks
if !isConfigBlock(anyBlock) { return errors.New("not a config block") }
meta, err := ConsensusMetadataFromConfigBlock(configBlock)
Defensive patterns

Strategy: validation

Validate before calling

func isConfigBlock(block *common.Block) bool {
	if block == nil || block.Data == nil || block.Header == nil {
		return false
	}
	env, err := utils.ExtractEnvelope(block, 0)
	if err != nil {
		return false
	}
	// a config block carries a CONFIG payload; rely on header type check
	return block.Header.Number >= 0 && env != nil
}

Try / catch

meta, err := ConsensusMetadataFromConfigBlock(block)
if err != nil {
	var wrapped interface{ Cause() error }
	if errors.As(err, &cause) { log.Debugf("root cause: %v", errors.Unwrap(err)) }
	return fmt.Errorf("block %d is not a valid config block: %w", block.Header.Number, err)
}

Prevention

When it happens

Trigger: Calling ConsensusMetadataFromConfigBlock with a block whose envelope payload is not a valid CONFIG transaction, is truncated, has been tampered with, or whose ConfigUpdate envelope is missing/unmarshalable.

Common situations: Passing a non-config (e.g. regular tx) block as a config block; a corrupt channel-config block on disk; feeding a block from a different channel type; proto schema/version mismatch between producer and consumer of the block.

Related errors


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