hyperledger/fabric · error
last config in block orderer metadata points to %d but our p
Error message
last config in block orderer metadata points to %d but our persisted last config is %d
What it means
The LastConfig.Index in the signed OrdererBlockMetadata must equal the verifier's computed/persisted last config block number. This error means the signature claims a different config block index than the verifying node's ledger says — i.e. the two nodes disagree about where the most recent configuration transaction lives, or the block references the wrong last-config pointer.
Source
Thrown at orderer/consensus/smartbft/verifier.go:315
metadataFromProposal.GetViewId(), metadataFromProposal.GetLatestSequence(),
metadataInBlock.GetViewId(), metadataInBlock.GetLatestSequence(),
)
}
rtc := v.RuntimeConfig.Load().(RuntimeConfig)
lastConfig := rtc.LastConfigBlock.Header.Number
if protoutil.IsConfigBlock(block) {
lastConfig = block.Header.Number
}
// Verify last config
if ordererMetadataFromSignature.LastConfig == nil {
return nil, errors.Errorf("last config is nil")
}
if ordererMetadataFromSignature.LastConfig.Index != lastConfig {
return nil, errors.Errorf("last config in block orderer metadata points to %d but our persisted last config is %d", ordererMetadataFromSignature.LastConfig.Index, lastConfig)
}
rawLastConfig, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG)
if err != nil {
return nil, err
}
lastConf := &cb.LastConfig{}
if err := proto.Unmarshal(rawLastConfig.Value, lastConf); err != nil {
return nil, err
}
if lastConf.Index != lastConfig {
return nil, errors.Errorf("last config in block metadata points to %d but our persisted last config is %d", ordererMetadataFromSignature.LastConfig.Index, lastConfig)
}
return validateTransactions(block.Data.Data, v.verifyRequest)
}
func validateTransactions(blockData [][]byte, verifyReq requestVerifier) ([]types.RequestInfo, error) {View on GitHub (pinned to 2736b63f8f)
Solutions
- Let the lagging node catch up: pull/replicate blocks from peers until its last config block matches the service's, then restart the orderer.
- Trigger a view change so the proposal is regenerated with the current last-config index.
- If ledgers have truly diverged, restore the node from a trusted snapshot or re-provision it from the ordering service.
- Verify channel config updates completed on all ordering nodes (check the config block number in each node's logs) before submitting more transactions.
- Check the log numbers: 'points to X but persisted Y' — if X < Y the proposer is stale; if X > Y the verifier is stale.
Example fix
// before: node's ledger last config lastConfig = 95; signature.LastConfig.Index = 100 -> error // after: catch up / resync node so its lastConfigIndex matches lastConfig = 100; signature.LastConfig.Index = 100
Defensive patterns
Strategy: validation
Validate before calling
if omd.GetLastConfig().GetIndex() != localLastConfigIndex {
// trigger catch-up/resync of this orderer before verifying further proposals
return fmt.Errorf("last config %d != local %d", omd.GetLastConfig().GetIndex(), localLastConfigIndex)
} Try / catch
if err := verifyProposal(prop); err != nil {
if strings.Contains(err.Error(), "points to ") && strings.Contains(err.Error(), "last config") {
go resyncLedgerFromService()
}
return err
} Prevention
- Ensure every config block is replicated to all orderers before further txs
- Monitor last-config index across orderers; alert on divergence
- Restore lagging nodes from snapshots instead of letting them verify stale proposals
When it happens
Trigger: VerifyProposal -> verifyBlockDataAndMetadata: ordererMetadataFromSignature.LastConfig.Index != lastConfig, where lastConfig comes from the verifier's persisted last config (or the block number itself when protoutil.IsConfigBlock(block) is true). Happens when a proposal is verified against a local ledger whose last config block differs from the proposer's.
Common situations: A lagging orderer that missed the most recent channel configuration update; channel config updated while a node was down and its recorded last-config index is stale; a proposal replayed from an earlier point in the chain; divergent ledgers after a snapshot restore.
Related errors
- last config in block metadata points to %d but our persisted
- last config is nil
- consenter options type mismatch
- failed to unmarshal BFT metadata configuration
- invalid BFT metadata configuration
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/e21b7d31a9378797.
Report an issue: GitHub.