{"record":{"id":"6ae25dddf0638c0c","repo":"linera-io/linera-protocol","slug":"failed-to-download-certificates-and-update-local-n","errorCode":null,"errorMessage":"Failed to download certificates and update local node to the next height {target_next_block_height} of chain {chain_id}","messagePattern":"Failed to download certificates and update local node to the next height (.+?) of chain (.+?)","errorType":"validation","errorClass":"ChainClientError","httpStatus":null,"severity":"error","filePath":"linera-core/src/client/mod.rs","lineNumber":692,"sourceCode":"                    self.options.certificate_batch_download_hedge_delay,\n                )\n                .await?;\n            let Some(new_info) = self\n                .process_certificates(\n                    &validators,\n                    certificates,\n                    None,\n                    ProcessConfirmedBlockMode::Execute,\n                )\n                .await?\n            else {\n                break;\n            };\n            assert!(new_info.next_block_height > next_height);\n            next_height = new_info.next_block_height;\n            info = new_info;\n        }\n        ensure!(\n            target_next_block_height <= info.next_block_height,\n            chain_client::Error::CannotDownloadCertificates {\n                chain_id,\n                target_next_block_height,\n            }\n        );\n        Ok(info)\n    }\n\n    /// Loads and processes certificates from local storage for the given chain, from the\n    /// current local height up to `end`. Returns the chain info after processing.\n    /// If `until_block_time` is `Some`, stops before processing any certificate whose\n    /// block timestamp is >= the given value (exclusive).\n    async fn load_local_certificates(\n        &self,\n        chain_id: ChainId,\n        end: BlockHeight,\n        until_block_time: Option<Timestamp>,","sourceCodeStart":674,"sourceCodeEnd":710,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-core/src/client/mod.rs#L674-L710","documentation":"Raised by Client::download_certificates when, after batching certificate downloads from the configured validators, the local node's next_block_height for the chain is still below target_next_block_height. The download loop breaks as soon as process_certificates stops advancing the height, then the final guard fails. It means the validator set collectively could not (or would not) serve the certificates needed to reach the target height.","triggerScenarios":"receive_certificate_with_checked_signatures on a certificate whose block is higher than what any known validator can prove; synchronize_to_known_height with a target beyond the validators' state; validators that pruned old certificates or are stuck on an older epoch; wallet pointing at a validator list from a different committee/epoch than the certificate's.","commonSituations":"Faucet or wallet transfers where the recipient client knows a certificate height the validators no longer serve; misconfigured validator endpoints (stale wallet config after a committee change); a validator proxy that answers but returns no usable certificates; network partition during initial chain sync.","solutions":["Retry later: validators may still be catching up with their peers and will serve the certificates afterwards","Check each validator's actual next_block_height via a chain_info query and lower the target to what is reachable, or wait for lagging validators","Update the wallet's validator/committee configuration so it matches the epoch of the certificate being processed","If a validator pruned history, fetch the missing certificates from another validator or proxy that still stores them"],"exampleFix":"// before\nlet info = client.download_certificates(chain_id, target_height).await?;\n\n// after\nlet info = match client.download_certificates(chain_id, target_height).await {\n    Ok(info) => info,\n    Err(chain_client::Error::CannotDownloadCertificates { chain_id, target_next_block_height }) => {\n        // Ask validators how far they actually are before retrying.\n        let reachable = client\n            .stage_and_check_validators_for_height(chain_id, target_next_block_height)\n            .await?;\n        client.download_certificates(chain_id, reachable.min(target_next_block_height)).await?\n    }\n    other => other?,\n};","handlingStrategy":"retry","validationCode":"// Before downloading to a target height, ask validators how far they actually are.\nasync fn reachable_height(client: &Client, chain_id: ChainId, target: BlockHeight) -> Result<BlockHeight, chain_client::Error> {\n    let info = client.local_node().chain_info(chain_id).await?;\n    // compare with validators' advertised next_block_height and pick the min\n    Ok(info.next_block_height.min(target))\n}","typeGuard":"fn cannot_download_certificates(err: &chain_client::Error) -> bool {\n    matches!(err, chain_client::Error::CannotDownloadCertificates { .. })\n}","tryCatchPattern":"let mut retries = 0;\nloop {\n    match client.download_certificates(chain_id, target).await {\n        Ok(info) => break info,\n        Err(chain_client::Error::CannotDownloadCertificates { target_next_block_height, .. }) if retries < 3 => {\n            retries += 1;\n            tokio::time::sleep(Duration::from_secs(5 * retries)).await; // validators may catch up\n        }\n        Err(e) => return Err(e.into()),\n    }\n}","preventionTips":["Keep the wallet's validator and committee configuration in sync with the current epoch before accepting certificates","Periodically synchronize chains you care about so targets stay within validators' retained history","Monitor validators' next_block_height; a validator far behind the target will make downloads fail"],"tags":["linera","sync","certificates","validators","network"],"backgroundTag":"block-not-found","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}