linera-io/linera-protocol · error · ChainClientError
Failed to download certificates and update local node to the
Error message
Failed to download certificates and update local node to the next height {target_next_block_height} of chain {chain_id} What it means
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.
Source
Thrown at linera-core/src/client/mod.rs:692
self.options.certificate_batch_download_hedge_delay,
)
.await?;
let Some(new_info) = self
.process_certificates(
&validators,
certificates,
None,
ProcessConfirmedBlockMode::Execute,
)
.await?
else {
break;
};
assert!(new_info.next_block_height > next_height);
next_height = new_info.next_block_height;
info = new_info;
}
ensure!(
target_next_block_height <= info.next_block_height,
chain_client::Error::CannotDownloadCertificates {
chain_id,
target_next_block_height,
}
);
Ok(info)
}
/// Loads and processes certificates from local storage for the given chain, from the
/// current local height up to `end`. Returns the chain info after processing.
/// If `until_block_time` is `Some`, stops before processing any certificate whose
/// block timestamp is >= the given value (exclusive).
async fn load_local_certificates(
&self,
chain_id: ChainId,
end: BlockHeight,
until_block_time: Option<Timestamp>,View on GitHub (pinned to 6c226ddcb3)
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
Example fix
// before
let info = client.download_certificates(chain_id, target_height).await?;
// after
let info = match client.download_certificates(chain_id, target_height).await {
Ok(info) => info,
Err(chain_client::Error::CannotDownloadCertificates { chain_id, target_next_block_height }) => {
// Ask validators how far they actually are before retrying.
let reachable = client
.stage_and_check_validators_for_height(chain_id, target_next_block_height)
.await?;
client.download_certificates(chain_id, reachable.min(target_next_block_height)).await?
}
other => other?,
}; Defensive patterns
Strategy: retry
Validate before calling
// Before downloading to a target height, ask validators how far they actually are.
async fn reachable_height(client: &Client, chain_id: ChainId, target: BlockHeight) -> Result<BlockHeight, chain_client::Error> {
let info = client.local_node().chain_info(chain_id).await?;
// compare with validators' advertised next_block_height and pick the min
Ok(info.next_block_height.min(target))
} Type guard
fn cannot_download_certificates(err: &chain_client::Error) -> bool {
matches!(err, chain_client::Error::CannotDownloadCertificates { .. })
} Try / catch
let mut retries = 0;
loop {
match client.download_certificates(chain_id, target).await {
Ok(info) => break info,
Err(chain_client::Error::CannotDownloadCertificates { target_next_block_height, .. }) if retries < 3 => {
retries += 1;
tokio::time::sleep(Duration::from_secs(5 * retries)).await; // validators may catch up
}
Err(e) => return Err(e.into()),
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Missing certificates for chain {chain_id} in heights {height
- Unexpected certificate value
- Local error handling validator response: validator still rep
- Cannot confirm a block before its predecessors: {current_blo
- Cannot vote for block proposal of chain {chain_id} because {
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/6ae25dddf0638c0c.
Report an issue: GitHub.