{"record":{"id":"e21b7d31a9378797","repo":"hyperledger/fabric","slug":"last-config-in-block-orderer-metadata-points-to-d","errorCode":null,"errorMessage":"last config in block orderer metadata points to %d but our persisted last config is %d","messagePattern":"last config in block orderer metadata points to (.+?) but our persisted last config is (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":315,"sourceCode":"\t\t\tmetadataFromProposal.GetViewId(), metadataFromProposal.GetLatestSequence(),\n\t\t\tmetadataInBlock.GetViewId(), metadataInBlock.GetLatestSequence(),\n\t\t)\n\t}\n\n\trtc := v.RuntimeConfig.Load().(RuntimeConfig)\n\tlastConfig := rtc.LastConfigBlock.Header.Number\n\n\tif protoutil.IsConfigBlock(block) {\n\t\tlastConfig = block.Header.Number\n\t}\n\n\t// Verify last config\n\tif ordererMetadataFromSignature.LastConfig == nil {\n\t\treturn nil, errors.Errorf(\"last config is nil\")\n\t}\n\n\tif ordererMetadataFromSignature.LastConfig.Index != lastConfig {\n\t\treturn nil, errors.Errorf(\"last config in block orderer metadata points to %d but our persisted last config is %d\", ordererMetadataFromSignature.LastConfig.Index, lastConfig)\n\t}\n\n\trawLastConfig, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlastConf := &cb.LastConfig{}\n\tif err := proto.Unmarshal(rawLastConfig.Value, lastConf); err != nil {\n\t\treturn nil, err\n\t}\n\tif lastConf.Index != lastConfig {\n\t\treturn nil, errors.Errorf(\"last config in block metadata points to %d but our persisted last config is %d\", ordererMetadataFromSignature.LastConfig.Index, lastConfig)\n\t}\n\n\treturn validateTransactions(block.Data.Data, v.verifyRequest)\n}\n\nfunc validateTransactions(blockData [][]byte, verifyReq requestVerifier) ([]types.RequestInfo, error) {","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L297-L333","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: node's ledger last config\nlastConfig = 95; signature.LastConfig.Index = 100  -> error\n// after: catch up / resync node so its lastConfigIndex matches\nlastConfig = 100; signature.LastConfig.Index = 100","handlingStrategy":"validation","validationCode":"if omd.GetLastConfig().GetIndex() != localLastConfigIndex {\n    // trigger catch-up/resync of this orderer before verifying further proposals\n    return fmt.Errorf(\"last config %d != local %d\", omd.GetLastConfig().GetIndex(), localLastConfigIndex)\n}","typeGuard":null,"tryCatchPattern":"if err := verifyProposal(prop); err != nil {\n    if strings.Contains(err.Error(), \"points to \") && strings.Contains(err.Error(), \"last config\") {\n        go resyncLedgerFromService()\n    }\n    return err\n}","preventionTips":["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"],"tags":["hyperledger-fabric","smartbft","last-config","ledger-divergence"],"backgroundTag":"last-config-index-mismatch","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}