linera-io/linera-protocol · error · NodeError

Local error handling validator response: validator still…

Error message

Local error handling validator response: validator still reports missing cross-chain updates for chain {dependencies_chain_id} after they were all synced

What it means

Raised in RemoteNodeUpdater::send_block_proposal: when a validator rejects a block proposal with MissingCrossChainUpdates, the client syncs every reported origin chain to the needed height and retries the proposal once. If the validator then reports missing cross-chain updates for the same chain again, the one-shot guard fires: retrying further cannot make progress, because the local node was unable to supply what the validator says it needs.

Solutions

  1. Fully synchronize the origin chains from other validators before proposing: download their certificates up to the reported heights
  2. Re-run prepare_chain() so the client's local node catches up with everything the validator references
  3. Check that client and validators run compatible linera versions (cross-chain bundle format changes)
  4. If the validator is simply broken, exclude it from the quorum set and retry
Defensive patterns

Strategy: retry

Type guard

fn is_cross_chain_sync_stuck(err: &chain_client::Error) -> bool {
    matches!(
        err,
        chain_client::Error::RemoteNodeError(NodeError::ResponseHandlingError { error })
            if error.contains("missing cross-chain updates")
    )
}

Try / catch

match client.execute_operations(operations, vec![]).await {
    Err(e) if is_cross_chain_sync_stuck(&e) => {
        // Sync all origin chains fully, then rebuild and retry the proposal.
        client.prepare_chain().await?;
        client.execute_operations(operations, vec![]).await
    }
    other => other,
}

Prevention

When it happens

Trigger: The local node does not actually hold the cross-chain message bundles the validator demands (the sync sent nothing useful for those origins); validator and client disagree on which bundles exist (version drift); validator storage state corrupted so it never accepts the bundles it is sent.

Common situations: Proposing a block that receives messages from chains the client never fully downloaded; clients restored from an old wallet/state trying to spend received funds; validator software downgrade or upgrade changing bundle accounting.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/3e8a45f4e893317d. Report an issue: GitHub.

Appendix: source

Thrown at linera-core/src/updater.rs:623

                    self.sync_remote_if_needed(
                        chain_id,
                        proposal.content.round,
                        proposal.content.block.height,
                        &err,
                    )
                    .await?;
                }
                // The validator reports *every* missing cross-chain bundle in a single
                // `MissingCrossChainUpdates`, so we sync all of them at once and retry. Some
                // received certificates may be missing for this validator (e.g. to create the
                // chain or make the balance sufficient). If it still reports missing bundles
                // after we synced the whole set, retrying would not make progress, so we surface
                // the error instead of looping.
                Err(NodeError::MissingCrossChainUpdates {
                    chain_id: dependencies_chain_id,
                    bundles,
                }) if dependencies_chain_id == proposal.content.block.chain_id => {
                    ensure!(
                        !synced_cross_chain_updates,
                        NodeError::ResponseHandlingError {
                            error: format!(
                                "validator still reports missing cross-chain updates for chain \
                                 {dependencies_chain_id} after they were all synced"
                            ),
                        }
                    );
                    synced_cross_chain_updates = true;
                    tracing::debug!(
                        remote_node = %self.remote_node.address(),
                        %chain_id,
                        bundles = bundles.len(),
                        "validator reported missing cross-chain updates; syncing them in one batch",
                    );
                    // Sync each reported origin chain up to the needed height, collapsing any
                    // duplicate origins to the highest height.
                    let mut origin_heights: BTreeMap<ChainId, BlockHeight> = BTreeMap::new();

View on GitHub (pinned to 6c226ddcb3)