{"record":{"id":"ba761a1b29485a31","repo":"linera-io/linera-protocol","slug":"invalidepoch","errorCode":"InvalidEpoch","errorMessage":"Unexpected epoch {epoch}: chain {chain_id} is at {chain_epoch}","messagePattern":"Unexpected epoch (.+?): chain (.+?) is at (.+?)","errorType":"validation","errorClass":"WorkerError","httpStatus":null,"severity":"error","filePath":"linera-core/src/chain_worker/state.rs","lineNumber":797,"sourceCode":"    ))]\n    pub(crate) async fn process_timeout(\n        &mut self,\n        certificate: TimeoutCertificate,\n    ) -> Result<(ChainInfoResponse, NetworkActions), WorkerError> {\n        // Check that the chain is active and ready for this timeout.\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 (chain_epoch, committee) = self.chain.current_committee().await?;\n        certificate.check(&committee)?;\n        if self\n            .chain\n            .tip_state\n            .get()\n            .already_validated_block(certificate.inner().height())?\n        {\n            return Ok((self.chain_info_response().await?, NetworkActions::default()));\n        }\n        ensure!(\n            certificate.inner().epoch() == chain_epoch,\n            WorkerError::InvalidEpoch {\n                chain_id: certificate.inner().chain_id(),\n                chain_epoch,\n                epoch: certificate.inner().epoch()\n            }\n        );\n        let old_round = self.chain.manager.current_round();\n        self.chain\n            .manager\n            .handle_timeout_certificate(certificate, self.storage.clock().current_time());\n        self.save().await?;\n        let actions = self.create_network_actions(Some(old_round)).await?;\n        Ok((self.chain_info_response().await?, actions))\n    }\n\n    /// Tries to load all blobs published in this proposal.\n    ///","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-core/src/chain_worker/state.rs#L779-L815","documentation":"process_timeout only accepts a timeout certificate whose epoch equals the chain's current epoch: the certificate's signatures were collected from a specific committee, and validators of a different epoch are no longer authoritative for this chain.","triggerScenarios":"Submitting a TimeoutCertificate minted under the previous committee after the chain already transitioned to a new epoch (or the certificate is from a future epoch the chain has not entered).","commonSituations":"Committee/epoch migration in progress; the receiving validator has not yet processed the latest admin-chain blocks that create the new epoch; replaying certificates captured before an epoch change; uneven admin-chain sync across validators.","solutions":["Bring the node's admin-chain state up to date so chain_epoch matches the certificate, then retry","Re-create the timeout certificate under the current epoch's committee","During epoch migrations, order operations so epoch-creating admin blocks are processed before dependent certificates are submitted"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Compare epochs before submitting a timeout certificate.\nlet info = client.chain_info(chain_id).await?;\nlet (chain_epoch, _) = current_committee_of(&info)?;\nif certificate.inner().epoch() != chain_epoch {\n    // Sync admin-chain state first, or mint a fresh certificate this epoch.\n    return sync_admin_chain(&client).await;\n}\nclient.submit_timeout_certificate(chain_id, certificate).await?;","typeGuard":"fn is_invalid_epoch(e: &WorkerError) -> bool {\n    matches!(e, WorkerError::InvalidEpoch { .. })\n}","tryCatchPattern":null,"preventionTips":["During committee migrations, process epoch-creating admin blocks on every node before submitting dependent certificates","Never replay certificates captured under a previous epoch","Surface the expected-vs-found epochs from the error to pinpoint which side is stale"],"tags":["consensus","epoch","committee-migration","timeout-certificate","linera"],"backgroundTag":"epoch-mismatch","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}