{"record":{"id":"377eea56fb225c51","repo":"linera-io/linera-protocol","slug":"unexpectedblockheight","errorCode":"UnexpectedBlockHeight","errorMessage":"Chain is expecting a next block at height {expected_block_height} but the given block is at height {found_block_height} instead","messagePattern":"Chain is expecting a next block at height (.+?) but the given block is at height (.+?) instead","errorType":"validation","errorClass":"ChainError","httpStatus":null,"severity":"error","filePath":"linera-core/src/chain_worker/state.rs","lineNumber":882,"sourceCode":"\n    /// Processes a validated block issued for this multi-owner chain.\n    #[instrument(skip_all, fields(\n        chain_id = %self.chain_id(),\n        block_height = %certificate.block().header.height\n    ))]\n    pub(crate) async fn process_validated_block(\n        &mut self,\n        certificate: ValidatedBlockCertificate,\n    ) -> Result<(ChainInfoResponse, NetworkActions, BlockOutcome), WorkerError> {\n        let block = certificate.block();\n\n        let header = &block.header;\n        let height = header.height;\n        // Check that the chain is active and ready for this validated block.\n        // Verify the certificate. Returns a catch-all error to make client code more robust.\n        self.initialize_and_save_if_needed().await?;\n        let tip_state = self.chain.tip_state.get();\n        ensure!(\n            header.height == tip_state.next_block_height,\n            ChainError::UnexpectedBlockHeight {\n                expected_block_height: tip_state.next_block_height,\n                found_block_height: header.height,\n            }\n        );\n        let (epoch, committee) = self.chain.current_committee().await?;\n        check_block_epoch(epoch, header.chain_id, header.epoch)?;\n        certificate.check(&committee)?;\n        let already_committed_block = self.chain.tip_state.get().already_validated_block(height)?;\n        let should_skip_validated_block = || {\n            self.chain\n                .manager\n                .check_validated_block(&certificate)\n                .map(|outcome| outcome == manager::Outcome::Skip)\n        };\n        if already_committed_block || should_skip_validated_block()? {\n            // If we just processed the same pending block, return the chain info unchanged.","sourceCodeStart":864,"sourceCodeEnd":900,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-core/src/chain_worker/state.rs#L864-L900","documentation":"process_validated_block requires the validated block's height to equal the chain's next_block_height exactly: validated certificates extend the chain one height at a time and must be applied in order. A certificate for a future height, or one for an already-passed height that is not covered by the skip paths, is rejected.","triggerScenarios":"process_validated_block (from handle_validated_request) with a certificate whose block height differs from tip_state.next_block_height — skipping heights, delivering out of order, or replaying old certificates after the tip advanced.","commonSituations":"Out-of-order certificate delivery during chain synchronization; client resuming from stale local state; duplicate submission after the block was already confirmed via another path.","solutions":["Process validated (and confirmed) block certificates strictly in height order, one per height","Query ChainInfo for next_block_height and submit the certificate that matches it","Drop certificates below next_block_height — their blocks are already applied"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Only deliver the certificate matching the chain's next height.\nlet info = client.chain_info(chain_id).await?;\nlet expected = info.manager.next_block_height;\nmatch certificate.block().header.height.cmp(&expected) {\n    Ordering::Equal => client.submit_validated(certificate).await?,\n    Ordering::Less => { /* already applied; drop it */ }\n    Ordering::Greater => { /* fetch and submit certificates for the gap first */ }\n}","typeGuard":"fn is_unexpected_block_height(e: &ChainError) -> bool {\n    matches!(e, ChainError::UnexpectedBlockHeight { .. })\n}","tryCatchPattern":"match client.submit_validated(certificate).await {\n    Err(e) if matches!(e, ref x if x.is_unexpected_block_height()) => {\n        // Re-query next_block_height, deliver the missing heights in order, then retry.\n    }\n    other => other?,\n}","preventionTips":["Deliver validated and confirmed certificates strictly in height order","Derive the next expected height from fresh ChainInfo, not from local counters","Drop certificates below next_block_height instead of resubmitting them"],"tags":["consensus","block-height","validated-certificate","ordering","linera"],"backgroundTag":"block-height-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}