{"record":{"id":"76be6995cbc0a821","repo":"linera-io/linera-protocol","slug":"cannot-vote-for-block-proposal-of-chain-chain-id","errorCode":null,"errorMessage":"Cannot vote for block proposal of chain {chain_id} because {} cross-chain message bundle(s) have not been received yet","messagePattern":"Cannot vote for block proposal of chain (.+?) because (.+?) cross-chain message bundle\\(s\\) have not been received yet","errorType":"validation","errorClass":"ChainError","httpStatus":null,"severity":"error","filePath":"linera-chain/src/chain.rs","lineNumber":771,"sourceCode":"                    .collect::<Vec<_>>()\n                    .join(\", \")\n            );\n            for bundle in bundles {\n                // Mark the message as processed in the inbox.\n                let was_present = inbox\n                    .remove_bundle(bundle)\n                    .await\n                    .map_err(|error| (chain_id, origin, error))?;\n                if must_be_present && !was_present {\n                    missing_bundles.push((origin, bundle.height));\n                }\n            }\n            inbox.observe_size_metric();\n            if inbox.added_bundles.count() == 0 {\n                self.nonempty_inboxes.get_mut().remove(&origin);\n            }\n        }\n        ensure!(\n            missing_bundles.is_empty(),\n            ChainError::MissingCrossChainUpdates {\n                chain_id,\n                bundles: missing_bundles,\n            }\n        );\n        Ok(())\n    }\n\n    /// Returns the chain IDs of all recipients for which a message is waiting in the outbox.\n    pub fn nonempty_outbox_chain_ids(&self) -> Vec<ChainId> {\n        self.nonempty_outboxes.get().iter().copied().collect()\n    }\n\n    /// Returns the outboxes for the given targets, or an error if any of them are missing.\n    pub async fn load_outboxes(\n        &self,\n        targets: &[ChainId],","sourceCodeStart":753,"sourceCodeEnd":789,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-chain/src/chain.rs#L753-L789","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: proposing immediately after the send confirms\nclient.propose_receive_block(bundles).await?; // -> MissingCrossChainUpdates\n\n// after: drive delivery, then retry\nmatch client.propose_receive_block(bundles.clone()).await {\n    Err(ChainError::MissingCrossChainUpdates { bundles: missing, .. }) => {\n        for (origin, height) in missing {\n            client.fetch_and_process_sender_block(origin, height).await?;\n        }\n        client.propose_receive_block(bundles).await?;\n    }\n    other => other?,\n}","handlingStrategy":"retry","validationCode":"// Before proposing a receive block, confirm the bundles are in the inbox\n// (the error itself lists exactly what is missing, so a pre-check is optional):\nlet pending = client.query_inbox_state(chain_id).await?;\nlet ready = block.incoming_bundles().all(|b| pending.contains(b.origin, b.bundle.height));\nif !ready {\n    client.synchronize_receive_logs(chain_id).await?; // pull cross-chain updates first\n}","typeGuard":null,"tryCatchPattern":"match client.propose(block).await {\n    Err(ChainError::MissingCrossChainUpdates { bundles: missing, .. }) => {\n        // `missing` is the exact [(origin, height)] set to fetch — pull those sender\n        // blocks, deliver them, then retry the identical proposal.\n        for (origin, height) in &missing {\n            client.fetch_and_process_sender_block(*origin, *height).await?;\n        }\n        client.propose(block).await?\n    }\n    other => other?,\n}","preventionTips":["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"],"tags":["linera","cross-chain","inbox","messages","sync","retryable","rust"],"backgroundTag":"cross-chain-message-not-received","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}