{"record":{"id":"e24b8e45c4d4ed7e","repo":"linera-io/linera-protocol","slug":"insufficientround","errorCode":"InsufficientRound","errorMessage":"Round number should be at least {0:?}","messagePattern":"Round number should be at least (.+?)","errorType":"validation","errorClass":"ChainError","httpStatus":null,"severity":"warning","filePath":"linera-chain/src/manager.rs","lineNumber":313,"sourceCode":"        // When a block is certified, incrementing its height must succeed.\n        ensure!(\n            new_block.height < BlockHeight::MAX,\n            ChainError::BlockHeightOverflow\n        );\n        let current_round = self.current_round();\n        match new_round {\n            // The proposal from the fast round may still be relevant as a locking block, so\n            // we don't compare against the current round here.\n            Round::Fast => {}\n            Round::MultiLeader(_) | Round::SingleLeader(0) => {\n                // If the fast round has not timed out yet, only a super owner is allowed to open\n                // a later round by making a proposal.\n                ensure!(\n                    self.is_super(&proposal.owner()) || !current_round.is_fast(),\n                    ChainError::WrongRound(current_round)\n                );\n                // After the fast round, proposals older than the current round are obsolete.\n                ensure!(\n                    new_round >= current_round,\n                    ChainError::InsufficientRound(new_round)\n                );\n            }\n            Round::SingleLeader(_) | Round::Validator(_) => {\n                // After the first single-leader round, only proposals from the current round are relevant.\n                ensure!(\n                    new_round == current_round,\n                    ChainError::WrongRound(current_round)\n                );\n            }\n        }\n        // The round of our validation votes is only allowed to increase.\n        if let Some(vote) = self.validated_vote() {\n            ensure!(\n                new_round > vote.round,\n                ChainError::InsufficientRoundStrict(vote.round)\n            );","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-chain/src/manager.rs#L295-L331","documentation":"In check_proposed_block, once past the fast round, a MultiLeader or SingleLeader(0) proposal from a round older than the manager's current round is obsolete. The manager only considers proposals at or above its current round, which advances via timeout certificates and newer proposals.","triggerScenarios":"Re-delivering or retrying a block proposal whose content.round is lower than manager.current_round() after the round moved forward (timeout certificate processed or a newer proposal seen).","commonSituations":"Retrying a failed proposal submission after the round advanced; client caching proposals across rounds; leader reusing a proposal computed before a timeout.","solutions":["Fetch fresh chain info and build a new proposal at (or above) the current round","Discard the stale proposal instead of retrying it unchanged"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let info = client.chain_info(chain_id).await?;\nif proposal.content.round < info.manager.current_round {\n    // Stale proposal: rebuild it at the current round instead of submitting.\n    return rebuild_proposal(&client, chain_id).await;\n}","typeGuard":"fn is_insufficient_round(e: &ChainError) -> bool {\n    matches!(e, ChainError::InsufficientRound(_))\n}","tryCatchPattern":null,"preventionTips":["Do not cache or retry proposals across rounds","Refresh chain info after any timeout event before re-proposing"],"tags":["consensus","round","stale-proposal","linera"],"backgroundTag":"consensus-round-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}