hyperledger/fabric · error
pending config does not match calculated expected config
Error message
pending config does not match calculated expected config
What it means
During a SmartBFT config update, the orderer re-applies the proposed config envelope through ProposeConfigUpdate to compute what the resulting config SHOULD be, then compares it byte-for-byte (proto.Equal) with the config the proposal actually carried. This error means the two diverged: the config in the submitted CONFIG transaction is not the one the current config would produce when the update is applied. It is thrown from verifyConfigUpdateMsg, reached via ValidateConfig, so the update is rejected and the channel config stays unchanged.
Source
Thrown at orderer/consensus/smartbft/configverifier.go:244
} else {
expectedConfigEnv, err = cbv.ConfigUpdateProposer.ProposeConfigUpdate(chdr.ChannelId, confEnv.LastUpdate)
if err != nil {
cbv.Logger.Errorf("Rejecting config proposal due to %v", err)
return err
}
}
if err := cbv.checkConsentersMatchPolicy(confEnv.Config); err != nil {
return err
}
// Extract the Config from the result of ProposeConfigUpdate, and compare it
// with the pending config.
if proto.Equal(confEnv.Config, expectedConfigEnv.Config) {
return nil
}
cbv.Logger.Errorf("Pending Config is %v, but it should be %v", confEnv.Config, expectedConfigEnv.Config)
return errors.Errorf("pending config does not match calculated expected config")
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Regenerate the CONFIG envelope from a fresh, current config block using configtxlator/transport: fetch latest config, apply the ConfigUpdate, recompute, re-sign — do not reuse an old CONFIG envelope
- Verify the ConfigUpdate was computed against the latest committed config sequence; refetch the newest config block and retry the update if another update changed the channel in between
- Check for concurrent config submitters on the channel and serialize updates
- Inspect the logger output 'Pending Config is %v, but it should be %v' to diff the submitted vs expected Config and find the mismatched field
Example fix
// before: reusing a stale CONFIG envelope fetched earlier oldBlock := fetchConfigBlock(channel) env := buildConfigEnvelopeFrom(oldBlock) // may mismatch current config submit(env) // after: always recompute from the latest committed config latestBlock := fetchLatestConfigBlock(channel) update := computeConfigUpdate(latestBlock, desiredChanges) env, _ := protoutil.CreateSignedEnvelope(..., update, ...) submit(env)
Defensive patterns
Strategy: validation
Validate before calling
// Recompute the expected config exactly like the orderer does, before submitting
expected, err := endorser.ProposeConfigUpdate(configUpdateEnv, channelID)
if err != nil { return err }
submitted, _ := extractConfig(confEnv)
if !proto.Equal(submitted, expected) {
return errors.New("config envelope is stale; recompute against latest config block")
}
submit(confEnv) Prevention
- Always derive the CONFIG envelope from the latest fetched config block, never reuse cached ones
- Serialize config updates — one submitter at a time per channel
- Use configtxlator to compute updates rather than hand-editing configs
- On failure, refetch the newest config block and retry with a recomputed update
When it happens
Trigger: A CONFIG envelope is proposed whose embedded Config message differs from the recomputed Config produced by ProposeConfigUpdate on the current committed config — e.g. a peer/orderer tampered with or hand-crafted the Config fields instead of deriving them from a ConfigUpdateEnvelope, or the proposal raced with another config change so the expected result shifted.
Common situations: A fabric config update (adding an org, changing batch size, certificate rotation) is submitted against a stale ConfigUpdate so the recomputed result differs; a malicious or buggy client signs a modified Config directly; two config updates race so the second one's expected config no longer matches; tooling that edits channel config blocks manually re-submits an inconsistent Config.
Related errors
- failed parsing smartbft configuration
- failed creating a new BFTChain
- cannot get HeightsByEndpoints
- no cluster members to synchronize with
- already at height of %d
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/a92d80a4c3c14ae7.
Report an issue: GitHub.