{"record":{"id":"fbd5c7f5506c26c5","repo":"canopy-network/canopy","slug":"quorum-certificate-not-found","errorCode":null,"errorMessage":"quorum certificate not found","messagePattern":"quorum certificate not found","errorType":"error_code","errorClass":"ErrStoreGet","httpStatus":null,"severity":"error","filePath":"store/indexer.go","lineNumber":869,"sourceCode":"\t}\n\theight := binary.BigEndian.Uint64(segments[2])\n\treturn &lib.Checkpoint{\n\t\tHeight:    height,\n\t\tBlockHash: value,\n\t}, nil\n}\n\n// HELPER CODE BELOW\n\n// getQC() gets the QC bytes from the DB and converts it into a QC object\nfunc (t *Indexer) getQC(heightKey []byte) (*lib.QuorumCertificate, lib.ErrorI) {\n\t// get from db\n\tbz, err := t.db.Get(heightKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(bz) == 0 {\n\t\treturn nil, ErrStoreGet(errors.New(\"quorum certificate not found\"))\n\t}\n\t// convert to QC object\n\tptr := new(lib.QuorumCertificate)\n\tif err = lib.Unmarshal(bz, ptr); err != nil {\n\t\treturn nil, err\n\t}\n\treturn ptr, nil\n}\n\n// getBlock() gets the block bytes from the DB and converts it into a filled BlockResult object including the transactions\nfunc (t *Indexer) getBlock(hashKey []byte, transactions bool) (*lib.BlockResult, lib.ErrorI) {\n\tbz, err := t.db.Get(hashKey)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif len(bz) == 0 {\n\t\treturn nil, ErrStoreGet(errors.New(\"block not found\"))\n\t}","sourceCodeStart":851,"sourceCodeEnd":887,"githubUrl":"https://github.com/canopy-network/canopy/blob/ee8197d91dd410f6592cb650a94c925ee6dc8bad/store/indexer.go#L851-L887","documentation":"Indexer.getQC returns \"quorum certificate not found\" (wrapped by ErrStoreGet) when the DB lookup for the QC at the given height returns zero bytes. It means no quorum certificate exists in the indexer for that height.","triggerScenarios":"GetQCByHeight called with a height above the latest finalized height, below the pruning horizon, or on a node that never stored the QC for that height.","commonSituations":"Polling a height before the node finalizes it; querying after pruning; pointing a client at a lagging or fresh (unsynced) node.","solutions":["Check the height against the node's latest finalized height before querying","Wait/retry until the node has finalized that height","Verify node sync and data retention if the height should be available"],"exampleFix":"// before\nqc, _ := idx.GetQCByHeight(h) // may not exist yet\n// after\nqc, err := idx.GetQCByHeight(h)\nif err != nil && strings.Contains(err.Error(), \"quorum certificate not found\") {\n\treturn pollLater(h) // retry after finalization\n}","handlingStrategy":"retry","validationCode":"latest := idx.GetLatestHeight()\nif height > latest { return errors.New(\"height not yet finalized\") }","typeGuard":null,"tryCatchPattern":"qc, errI := idx.GetQCByHeight(height)\nif errI != nil {\n\tif strings.Contains(errI.Error(), \"quorum certificate not found\") {\n\t\treturn waitForFinalization(height) // poll with backoff\n\t}\n\treturn nil, errI\n}","preventionTips":["Clamp query heights to the node's latest finalized height","Account for pruning before querying historical heights","Verify node sync status before querying recent heights"],"tags":["store","indexer","consensus","not-found"],"backgroundTag":"record-not-found","analyzedSha":"ee8197d91dd410f6592cb650a94c925ee6dc8bad","analyzedAt":"2026-09-06T09:30:15.973Z","contentChangedAt":"2026-09-06T09:30:15.973Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}