{"record":{"id":"339396ad54a76731","repo":"hyperledger/fabric","slug":"last-config-in-block-metadata-points-to-d-but-our","errorCode":null,"errorMessage":"last config in block metadata points to %d but our persisted last config is %d","messagePattern":"last config in block metadata points to (.+?) but our persisted last config is (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":327,"sourceCode":"\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) {\n\tvar validationFinished sync.WaitGroup\n\tvalidationFinished.Add(len(blockData))\n\n\ttype txnValidation struct {\n\t\tindexInBlock  int\n\t\textractedInfo types.RequestInfo\n\t\tvalidationErr error\n\t}\n\n\tnoConfigAllowed := len(blockData) > 1\n\n\tvalidations := make(chan txnValidation, len(blockData))","sourceCodeStart":309,"sourceCodeEnd":345,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L309-L345","documentation":"Besides the signed OrdererBlockMetadata, the block itself embeds a LAST_CONFIG entry in its metadata whose LastConfig.Index must match the computed last config. This error means the LAST_CONFIG metadata inside the block points to a different block number than the persisted/signed last config. Note the error message uses the signed metadata's index in the text, which can look confusing — the failing comparison is lastConf.Index != lastConfig.","triggerScenarios":"VerifyProposal -> verifyBlockDataAndMetadata: after unmarshalling cb.LastConfig from the block's BlockMetadataIndex_LAST_CONFIG entry, lastConf.Index != lastConfig. Occurs when the block's LAST_CONFIG metadata slice was built against a different last-config block number than the one the verifier computed.","commonSituations":"Ledger divergence between proposer and verifier; a block crafted by a node that computed last config from stale state; manual block edits or corrupted metadata; replayed blocks after a channel reconfiguration.","solutions":["Resync/replay the ledger on the node so its last-config index matches the chain, then restart.","Force a view change to get a proposal regenerated from consistent state.","Check for ledger corruption (compare block hashes/numbers across orderers) and restore from a snapshot if the block's LAST_CONFIG entry is damaged.","Ensure all consenters processed the same configuration transactions in the same order before continuing."],"exampleFix":"// before: block metadata LAST_CONFIG disagrees with ledger\nlastConf.Index = 90; lastConfig = 100 -> error\n// after: rebuild/resync so the block's LAST_CONFIG points at the real config block\nlastConf.Index = 100; lastConfig = 100","handlingStrategy":"validation","validationCode":"lc := &common.LastConfig{}\nif err := proto.Unmarshal(rawLastConfig.Value, lc); err != nil { return err }\nif lc.Index != expectedLastConfig {\n    return fmt.Errorf(\"block LAST_CONFIG %d != expected %d\", lc.Index, expectedLastConfig)\n}","typeGuard":null,"tryCatchPattern":"if err := verifyProposal(prop); err != nil {\n    if strings.Contains(err.Error(), \"last config in block metadata\") {\n        // resync ledger / force view change\n    }\n    return err\n}","preventionTips":["Compare block hashes across orderers periodically to detect divergence early","Never edit block metadata manually","Re-run config updates only when all orderers are in sync"],"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"}