{"record":{"id":"8cae0fb468c3b9dd","repo":"linera-io/linera-protocol","slug":"missingcertificates","errorCode":"MissingCertificates","errorMessage":"NodeError::MissingCertificates(missing_hashes)","messagePattern":"NodeError::MissingCertificates\\(missing_hashes\\)","errorType":"exception","errorClass":"NodeError","httpStatus":null,"severity":"error","filePath":"linera-rpc/src/grpc/client.rs","lineNumber":581,"sourceCode":"                missing\n            )?)?\n            .into_iter()\n            .map(|cert| {\n                ConfirmedBlockCertificate::try_from(cert)\n                    .map_err(|_| NodeError::UnexpectedCertificateValue)\n            })\n            .collect::<Result<_, _>>()?;\n\n            // In the case of the server not returning any certificates, we break the loop.\n            if received.is_empty() {\n                break;\n            }\n\n            // Honest validator should return certificates in the same order as the requested hashes.\n            missing_hashes = missing_hashes[received.len()..].to_vec();\n            certs_collected.append(&mut received);\n        }\n        ensure!(\n            missing_hashes.is_empty(),\n            NodeError::MissingCertificates(missing_hashes)\n        );\n        Ok(certs_collected)\n    }\n\n    #[instrument(target = \"grpc_client\", skip(self), err(level = Level::DEBUG), fields(address = self.address))]\n    async fn download_certificates_by_heights(\n        &self,\n        chain_id: ChainId,\n        heights: Vec<BlockHeight>,\n    ) -> Result<Vec<ConfirmedBlockCertificate>, NodeError> {\n        let mut missing = heights.into_iter().collect::<BTreeSet<_>>();\n        let mut certs_collected = vec![];\n        while !missing.is_empty() {\n            let request = CertificatesByHeightRequest {\n                chain_id,\n                heights: missing.iter().copied().collect(),","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-rpc/src/grpc/client.rs#L563-L599","documentation":"GrpcClient::download_certificates requests certificates from a validator in batches by hash, expecting honest validators to return them in request order; each round trims the requested-hash list by the number received. NodeError::MissingCertificates(missing_hashes) is raised when, after all rounds, some requested certificate hashes were still not delivered.","triggerScenarios":"Asking a validator for certificates it does not hold: hashes beyond its highest processed block height, pruned blocks, a wrong shard, or a validator returning fewer certificates than requested without an error.","commonSituations":"Syncing a client or worker from a validator that lags behind the requested heights; querying block hashes that do not exist on that network (mismatched genesis); aggressive pruning on validators; degraded networks returning short batches.","solutions":["Retry the download against a fully synced committee validator; the error payload lists exactly which hashes are still missing","Wait for the validator to process those heights, then re-request only the missing hashes","Confirm client and validator share the same genesis configuration (same chain, same committee)","If blocks were pruned, obtain them from a validator configured for archive/long retention"],"exampleFix":"// before\nlet certs = client.download_certificates(&hashes).await?; // MissingCertificates from a lagging validator\n\n// after\nlet certs = loop {\n    match client.download_certificates(&hashes).await {\n        Ok(certs) => break certs,\n        Err(NodeError::MissingCertificates(missing)) if attempt < 5 => {\n            tokio::time::sleep(backoff(attempt)).await; // let the validator catch up\n            hashes = missing; // only re-request what is still missing\n            attempt += 1;\n        }\n        Err(e) => return Err(e.into()),\n    }\n};","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch NodeError::MissingCertificates, read the missing_hashes from the error, sleep a backoff interval (validators often only need time to catch up), and re-issue download_certificates with just the missing hashes; after a few failures, switch to a different, fully synced validator endpoint.","preventionTips":["Sync from committee-member validators that are fully caught up","Keep the genesis configuration identical between client and validators","Check the validator's processed block height before requesting high blocks"],"tags":["grpc","certificates","sync","validator","linera-rpc"],"backgroundTag":"peer-missing-certificates","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}