{"record":{"id":"4849c2dd302bf393","repo":"hyperledger/fabric","slug":"not-found","errorCode":null,"errorMessage":"not found","messagePattern":"not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"common/deliverclient/blocksprovider/bft_header_receiver.go","lineNumber":204,"sourceCode":"\t\thr.logger.Infof(\"[%s][%s] Already stopped\", hr.chainID, hr.endpoint)\n\t\treturn nil\n\t}\n\n\thr.logger.Infof(\"[%s][%s] Stopping\", hr.chainID, hr.endpoint)\n\thr.stop = true\n\thr.clientCloserFunc()\n\tclose(hr.stopChan)\n\n\treturn nil\n}\n\n// LastBlockNum returns the last block number which was verified\nfunc (hr *BFTHeaderReceiver) LastBlockNum() (uint64, time.Time, error) {\n\thr.mutex.Lock()\n\tdefer hr.mutex.Unlock()\n\n\tif hr.lastHeader == nil {\n\t\treturn 0, time.Time{}, errors.New(\"not found\")\n\t}\n\n\treturn hr.lastHeader.Header.Number, hr.lastHeaderTime, nil\n}\n\n// LastBlock returns the last block which was verified\nfunc (hr *BFTHeaderReceiver) LastBlock() (*common.Block, time.Time, error) {\n\thr.mutex.Lock()\n\tdefer hr.mutex.Unlock()\n\n\tif hr.lastHeader == nil {\n\t\treturn nil, time.Time{}, errors.New(\"not found\")\n\t}\n\n\treturn hr.lastHeader, hr.lastHeaderTime, nil\n}\n","sourceCodeStart":186,"sourceCodeEnd":221,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/deliverclient/blocksprovider/bft_header_receiver.go#L186-L221","documentation":"BFTHeaderReceiver.LastBlockNum returns errors.New(\"not found\") when hr.lastHeader is nil, i.e. no block header has been received/verified yet. It is a sentinel state error, not a transport failure: the receiver simply has no cached last block number. Callers like newHeaderClient use it to seed the starting block number.","triggerScenarios":"newHeaderClient calls LastBlockNum on a freshly created BFTHeaderReceiver before any header has been verified, or after a state where lastHeader was never set; the method returns (0, zero time, \"not found\").","commonSituations":"Cold start of the censorship monitor on a channel where this receiver has not yet processed any blocks; initializing a new header receiver after channel join; callers not treating 'not found' as an expected first-call condition.","solutions":["Treat the \"not found\" error as an expected cold-start signal: fall back to a known ledger height or start block instead of failing.","Ensure the header receiver has been started/fed blocks (Start/Initialize path) before querying LastBlockNum.","If persistence is expected, verify the monitor was not recreated without restoring lastHeader from the ledger."],"exampleFix":"// before\nlastNum, _, err := hr.LastBlockNum()\nif err != nil {\n    return err\n}\n// after\nlastNum, _, err := hr.LastBlockNum()\nif err != nil {\n    if err.Error() == \"not found\" {\n        lastNum = ledgerHeight - 1 // cold start fallback\n    } else {\n        return err\n    }\n}","handlingStrategy":"fallback","validationCode":"// check whether the receiver has state before querying\nfunc hasLastHeader(hr *BFTHeaderReceiver) bool {\n    _, _, err := hr.LastBlockNum()\n    return err == nil // false => uninitialized, use ledger height instead\n}","typeGuard":"func lastBlockNumKnown(err error) bool {\n    return err == nil || !strings.Contains(err.Error(), \"not found\")\n}","tryCatchPattern":"num, ts, err := hr.LastBlockNum()\nif err != nil {\n    if strings.Contains(err.Error(), \"not found\") {\n        num, ts = seedFromLedgerHeight(), time.Time{} // cold-start fallback\n    } else {\n        return err\n    }\n}","preventionTips":["Seed header receivers from ledger height on startup instead of assuming prior state.","Persist last verified header across restarts if continuity matters.","Write tests covering first-call (cold) behavior of LastBlockNum/LastBlock."],"tags":["state","cold-start","bft","fabric"],"backgroundTag":"resource-not-found","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"}