linera-io/linera-protocol · error · ChainError
Cannot vote for block proposal of chain {chain_id} because {
Error message
Cannot vote for block proposal of chain {chain_id} because {} cross-chain message bundle(s) have not been received yet What it means
On the proposal path (must_be_present=true), remove_bundles_from_inboxes collects every (origin, height) pair whose bundle is not yet in the chain's inbox and fails with MissingCrossChainUpdates listing them all (linera-chain/src/chain.rs:743-777, comment: 'so the caller can be told the full set of cross-chain updates to fetch in a single round-trip'). A block cannot receive messages the local chain state has not yet been delivered via cross-chain updates.
Source
Thrown at linera-chain/src/chain.rs:771
.collect::<Vec<_>>()
.join(", ")
);
for bundle in bundles {
// Mark the message as processed in the inbox.
let was_present = inbox
.remove_bundle(bundle)
.await
.map_err(|error| (chain_id, origin, error))?;
if must_be_present && !was_present {
missing_bundles.push((origin, bundle.height));
}
}
inbox.observe_size_metric();
if inbox.added_bundles.count() == 0 {
self.nonempty_inboxes.get_mut().remove(&origin);
}
}
ensure!(
missing_bundles.is_empty(),
ChainError::MissingCrossChainUpdates {
chain_id,
bundles: missing_bundles,
}
);
Ok(())
}
/// Returns the chain IDs of all recipients for which a message is waiting in the outbox.
pub fn nonempty_outbox_chain_ids(&self) -> Vec<ChainId> {
self.nonempty_outboxes.get().iter().copied().collect()
}
/// Returns the outboxes for the given targets, or an error if any of them are missing.
pub async fn load_outboxes(
&self,
targets: &[ChainId],View on GitHub (pinned to 6c226ddcb3)
Solutions
- Use the error payload: for each missing (origin, height), fetch the sender's confirmed block and run it through the recipient worker's cross-chain update handling, then retry the proposal
- Wait for the inbox to be synced (query chain info for pending inbox state) before proposing the receive block
- Retry the identical proposal after delivery completes — the error is transient by design
Example fix
// before: proposing immediately after the send confirms
client.propose_receive_block(bundles).await?; // -> MissingCrossChainUpdates
// after: drive delivery, then retry
match client.propose_receive_block(bundles.clone()).await {
Err(ChainError::MissingCrossChainUpdates { bundles: missing, .. }) => {
for (origin, height) in missing {
client.fetch_and_process_sender_block(origin, height).await?;
}
client.propose_receive_block(bundles).await?;
}
other => other?,
} Defensive patterns
Strategy: retry
Validate before calling
// Before proposing a receive block, confirm the bundles are in the inbox
// (the error itself lists exactly what is missing, so a pre-check is optional):
let pending = client.query_inbox_state(chain_id).await?;
let ready = block.incoming_bundles().all(|b| pending.contains(b.origin, b.bundle.height));
if !ready {
client.synchronize_receive_logs(chain_id).await?; // pull cross-chain updates first
} Try / catch
match client.propose(block).await {
Err(ChainError::MissingCrossChainUpdates { bundles: missing, .. }) => {
// `missing` is the exact [(origin, height)] set to fetch — pull those sender
// blocks, deliver them, then retry the identical proposal.
for (origin, height) in &missing {
client.fetch_and_process_sender_block(*origin, *height).await?;
}
client.propose(block).await?
}
other => other?,
} Prevention
- Drive cross-chain delivery (process inbox / receive logs) before building receive blocks
- Treat MissingCrossChainUpdates as the shopping list it is designed to be — one round-trip fetches all of it
- After node restarts, sync inboxes before proposing
When it happens
Trigger: Proposing a receive block immediately after the sender's block confirmed, before the recipient validator processed the sender's cross-chain updates; a node restarted without syncing inboxes; message delivery racing block proposal construction.
Common situations: High-latency cross-chain message delivery in test nets or geographically spread validators; clients building receive-blocks eagerly after sending; inbox state lost or pruned after a storage restore.
Related errors
- Incoming message bundle in block proposed to {chain_id} has
- Local error handling validator response: validator still rep
- Cannot confirm a block before its predecessors: {current_blo
- Empty blocks are not allowed
- Events not found: {0:?}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/76be6995cbc0a821.
Report an issue: GitHub.