{"record":{"id":"91a961456dcd40e4","repo":"hyperledger/fabric","slug":"cannot-find-recent-collection-config-update-below","errorCode":null,"errorMessage":"cannot find recent collection config update below block sequence = %d, collection name = <%s> for chaincode <%s>","messagePattern":"cannot find recent collection config update below block sequence = (.+?), collection name = <(.+?)> for chaincode <(.+?)>","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gossip/privdata/dataretriever.go","lineNumber":147,"sourceCode":"\t\t\t// private data doesn't hold rwsets for namespace and collection or\n\t\t\t// belongs to different transaction\n\t\t\tif !data.Has(dig.Namespace, dig.Collection) || data.SeqInBlock != dig.SeqInBlock {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tpvtRWSet := dr.extractPvtRWsets(data.WriteSet.NsPvtRwset, dig.Namespace, dig.Collection)\n\t\t\tpvtRWSetWithConfig.RWSet = append(pvtRWSetWithConfig.RWSet, pvtRWSet...)\n\t\t}\n\n\t\tconfHistoryRetriever, err := dr.committer.GetConfigHistoryRetriever()\n\t\tif err != nil {\n\t\t\treturn nil, errors.Errorf(\"cannot obtain configuration history retriever, for collection <%s>\"+\n\t\t\t\t\" txID <%s> block sequence number <%d> due to <%s>\", dig.Collection, dig.TxId, dig.BlockSeq, err)\n\t\t}\n\n\t\tconfigInfo, err := confHistoryRetriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Errorf(\"cannot find recent collection config update below block sequence = %d,\"+\n\t\t\t\t\" collection name = <%s> for chaincode <%s>\", dig.BlockSeq, dig.Collection, dig.Namespace)\n\t\t}\n\n\t\tif configInfo == nil {\n\t\t\treturn nil, errors.Errorf(\"no collection config update below block sequence = <%d>\"+\n\t\t\t\t\" collection name = <%s> for chaincode <%s> is available \", dig.BlockSeq, dig.Collection, dig.Namespace)\n\t\t}\n\t\tconfigs := extractCollectionConfig(configInfo.CollectionConfig, dig.Collection)\n\t\tif configs == nil {\n\t\t\treturn nil, errors.Errorf(\"no collection config was found for collection <%s>\"+\n\t\t\t\t\" namespace <%s> txID <%s>\", dig.Collection, dig.Namespace, dig.TxId)\n\t\t}\n\t\tpvtRWSetWithConfig.CollectionConfig = configs\n\t\tresults[common.DigKey{\n\t\t\tNamespace:  dig.Namespace,\n\t\t\tCollection: dig.Collection,\n\t\t\tTxId:       dig.TxId,\n\t\t\tBlockSeq:   dig.BlockSeq,","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/gossip/privdata/dataretriever.go#L129-L165","documentation":"MostRecentCollectionConfigBelow searches the collection-config history for the latest configuration recorded before the given block sequence. If it returns an error, the retriever wraps it as 'cannot find recent collection config update below block sequence ...'. Without a historical config, the pvt-data access policy cannot be evaluated for the old transaction.","triggerScenarios":"ConfHistoryRetriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace) errors — usually the config history DB lacks entries (history wasn't recorded for that range) or the DB read fails.","commonSituations":"Private data requested for a very old transaction whose config history was purged; config history DB missing records after a restore from a partial backup; requesting data for a collection that had no config at that block height.","solutions":["Verify the collection config update event exists at/below that block in the config history DB.","Rebuild the peer databases (`peer node rebuild-dbs`) after restoring from a full, consistent backup.","Re-fetch private data from another peer that has complete config history.","If data was purged by retention policy, restore it or rely on reconciliation from a peer with full history."],"exampleFix":"// before: hard failure on missing config\nconfigInfo, err := confHistoryRetriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace)\n\n// after: skip digest when history is missing\nconfigInfo, err := confHistoryRetriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace)\nif err != nil {\n    logger.Warningf(\"no config history for %s at seq %d, skipping\", dig.Namespace, dig.BlockSeq)\n    continue\n}","handlingStrategy":"fallback","validationCode":"retriever, err := committer.GetConfigHistoryRetriever()\nif err == nil {\n    if _, err := retriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace); err != nil {\n        logger.Warningf(\"no config below seq %d for %s\", dig.BlockSeq, dig.Namespace)\n    }\n}","typeGuard":"func hasConfigBelow(r ledger.ConfigHistoryRetriever, seq uint64, ns string) bool {\n    _, err := r.MostRecentCollectionConfigBelow(seq, ns)\n    return err == nil\n}","tryCatchPattern":"configInfo, err := retriever.MostRecentCollectionConfigBelow(dig.BlockSeq, dig.Namespace)\nif err != nil {\n    logger.Warningf(\"falling back to another peer for pvt data of %s@%d\", dig.Namespace, dig.BlockSeq)\n    return fallbackFetch(dig)\n}","preventionTips":["Never restore peer DBs from partial backups — config history must be complete.","Only request pvt data at block heights where the collection was already defined.","Avoid purging config history for old blocks still under reconciliation.","Verify collection lifecycle ordering: config update commit before pvt-data requests."],"tags":["fabric","ledger","collection-config","private-data"],"backgroundTag":"collection-config-history-missing","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"}