{"record":{"id":"9aaca73a37db71d8","repo":"linera-io/linera-protocol","slug":"insufficientround-9aaca7","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/pending_blobs.rs","lineNumber":79,"sourceCode":"    pub async fn maybe_insert(&mut self, blob: &Blob) -> Result<bool, ViewError> {\n        let blob_id = blob.id();\n        let Some(maybe_blob) = self.pending_blobs.get_mut(&blob_id).await? else {\n            return Ok(false);\n        };\n        if maybe_blob.is_none() {\n            *maybe_blob = Some(blob.clone());\n        }\n        Ok(true)\n    }\n\n    pub fn update(\n        &mut self,\n        round: Round,\n        validated: bool,\n        maybe_blobs: BTreeMap<BlobId, Option<Blob>>,\n    ) -> Result<(), ChainError> {\n        let existing_round = *self.round.get();\n        ensure!(\n            existing_round <= round,\n            ChainError::InsufficientRound(existing_round)\n        );\n        if existing_round < round {\n            self.clear();\n            self.round.set(round);\n            self.validated.set(validated);\n        }\n        for (blob_id, maybe_blob) in maybe_blobs {\n            self.pending_blobs.insert(&blob_id, maybe_blob)?;\n        }\n        Ok(())\n    }\n}\n","sourceCodeStart":61,"sourceCodeEnd":94,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-chain/src/pending_blobs.rs#L61-L94","documentation":"PendingBlobsView::update maintains the blobs a validator is still waiting on for the pending block at a given round. It refuses updates carrying a round lower than the recorded one: blob content submitted for an obsolete round is discarded as stale, while a strictly newer round clears the old pending set before inserting.","triggerScenarios":"Uploading pending blob content (after a proposal returned BlobsNotFound and the worker registered pending blobs via load_proposal_blobs) using the round of an older proposal, after a proposal in a higher round re-registered pending blobs.","commonSituations":"Retrying blob uploads from stale client state after the leader re-proposed in a higher round; concurrent proposals from different owners on permissionless multi-leader chains; duplicate submissions racing round advancement.","solutions":["Re-fetch chain info; if the round moved, re-submit the current block proposal so pending blobs track the new round, then upload the blob content","Drop stale blob-upload retries when the recorded round has moved past your proposal's round"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before uploading pending blob content, confirm the round still matches.\nlet info = client.chain_info(chain_id).await?;\nif info.manager.pending_blobs.round > my_proposal_round {\n    // A newer proposal registered its blobs: refresh state before uploading.\n    return resubmit_current_proposal(&client, chain_id).await;\n}\nclient.upload_blob(chain_id, blob).await?;","typeGuard":"fn is_insufficient_round(e: &ChainError) -> bool {\n    matches!(e, ChainError::InsufficientRound(_))\n}","tryCatchPattern":null,"preventionTips":["Treat blob upload and proposal submission as one unit: after any round change, re-submit the proposal first, then upload blobs","Discard queued blob uploads whose round no longer matches the chain's pending round"],"tags":["consensus","round","blobs","pending-blobs","linera"],"backgroundTag":"consensus-round-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}