{"record":{"id":"9b12d10ff341a268","repo":"linera-io/linera-protocol","slug":"cannot-confirm-a-block-before-its-predecessors-c","errorCode":null,"errorMessage":"Cannot confirm a block before its predecessors: {current_block_height:?}","messagePattern":"Cannot confirm a block before its predecessors: (.+?)","errorType":"validation","errorClass":"ChainError","httpStatus":null,"severity":"error","filePath":"linera-chain/src/chain.rs","lineNumber":430,"sourceCode":"    pub fn verify_block_chaining(&self, new_block: &ProposedBlock) -> Result<(), ChainError> {\n        ensure!(\n            new_block.height == self.next_block_height,\n            ChainError::UnexpectedBlockHeight {\n                expected_block_height: self.next_block_height,\n                found_block_height: new_block.height\n            }\n        );\n        ensure!(\n            new_block.previous_block_hash == self.block_hash,\n            ChainError::UnexpectedPreviousBlockHash\n        );\n        Ok(())\n    }\n\n    /// Returns `true` if the validated block's height is below the tip height. Returns an error if\n    /// it is higher than the tip.\n    pub fn already_validated_block(&self, height: BlockHeight) -> Result<bool, ChainError> {\n        ensure!(\n            self.next_block_height >= height,\n            ChainError::MissingEarlierBlocks {\n                current_block_height: self.next_block_height,\n            }\n        );\n        Ok(self.next_block_height > height)\n    }\n}\n\nimpl<C> ChainStateView<C>\nwhere\n    C: Context + Clone + 'static,\n    C::Extra: ExecutionRuntimeContext,\n{\n    /// Returns the [`ChainId`] of the chain this [`ChainStateView`] represents.\n    pub fn chain_id(&self) -> ChainId {\n        self.context().extra().chain_id()\n    }","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-chain/src/chain.rs#L412-L448","documentation":"ChainTipState::already_validated_block (linera-chain/src/chain.rs:429-437) errors with MissingEarlierBlocks when a certificate's height is strictly above the chain's next_block_height — the chain is missing one or more predecessor blocks, so the certificate cannot be processed yet. It is the gatekeeper for process_timeout (linera-core/src/chain_worker/state.rs:793) and process_validated_block (state.rs:892), both of which must receive certificates in height order. This is a synchronization error, not a permanent rejection: once the gap is filled, the same certificate will process.","triggerScenarios":"Delivering a ValidatedBlockCertificate or TimeoutCertificate for height 10 while the local chain state is at next_block_height 7; a validator that skipped/restarted and lost heights receiving current certificates; cross-chain message handling that delivers a recipient update before the sender's earlier blocks were processed.","commonSituations":"Validators lagging behind the leader and receiving newer certificates first; network reordering; client submitting a higher block without first syncing handle_confirmed_block for the missing heights; storage restored from an old snapshot.","solutions":["Fetch and process the missing confirmed blocks (query the sender chain or peer validators) up to the certificate's height, then resubmit the certificate","Ensure your delivery layer processes blocks in height order per chain","Retry the same certificate after synchronization — it is not poisoned","If a node persistently lags, check its storage health and catch it up via a full chain query"],"exampleFix":"// before: submitting the certificate directly\nworker.handle_validated_certificate(cert).await?;\n\n// after: fill the gap first, then retry\nlet tip = chain_info.next_block_height;\nif cert.block().header.height > tip {\n    for h in tip..cert.block().header.height {\n        let missing = fetch_confirmed_block(chain_id, h).await?;\n        worker.handle_confirmed_certificate(missing).await?;\n    }\n}\nworker.handle_validated_certificate(cert).await?;","handlingStrategy":"retry","validationCode":"// Before submitting a certificate, check the chain can anchor it:\nlet next = chain_info.next_block_height;\nif cert_height > next {\n    // gap: process confirmed blocks [next, cert_height) first\n    for h in next..cert_height {\n        let block = fetch_confirmed_block(chain_id, h).await?;\n        worker.handle_confirmed_block(block).await?;\n    }\n}","typeGuard":null,"tryCatchPattern":"match worker.handle_certificate(cert).await {\n    Err(WorkerError::ChainError(ChainError::MissingEarlierBlocks { current_block_height })) => {\n        // sync missing heights (current_block_height..cert height), then retry the SAME certificate\n    }\n    other => other?,\n}","preventionTips":["Deliver blocks and certificates in height order per chain","After a node restart or storage restore, catch up before processing live traffic","Remember this error is transient — the certificate becomes processable once the gap is filled"],"tags":["linera","sync","block-height","gap","certificate","rust"],"backgroundTag":"out-of-order-block-delivery","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}