{"record":{"id":"542075abff9f3f41","repo":"nautechsystems/nautilus_trader","slug":"pre-sign-decision-header-precedes-the-trusted-chec","errorCode":null,"errorMessage":"Pre-sign decision header precedes the trusted checkpoint","messagePattern":"Pre-sign decision header precedes the trusted checkpoint","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":2518,"sourceCode":"        Ok(vec![\n            verification_decision(\n                &checkpoint,\n                Some(checkpoint.value.number),\n                Some(checkpoint.value.number),\n            ),\n            verification_decision(&header, Some(target.number), Some(target.number)),\n        ])\n    }\n\n    async fn verify_decision_ancestry(\n        &self,\n        target: VerifiedBlockHeader,\n    ) -> anyhow::Result<Vec<ExecutionVerificationDecision>> {\n        let checkpoint = required_verification(\n            self.verification.verify_checkpoint().await,\n            \"pre-sign checkpoint\",\n        )?;\n        anyhow::ensure!(\n            checkpoint.value.number <= target.number,\n            \"Pre-sign decision header precedes the trusted checkpoint\"\n        );\n        let mut decisions = vec![verification_decision(\n            &checkpoint,\n            Some(checkpoint.value.number),\n            Some(checkpoint.value.number),\n        )];\n        let wallet_address = self.wallet_address.to_string();\n        let position = self\n            .database\n            .load_execution_verification_position(\n                self.chain_id,\n                &wallet_address,\n                &self.manifest_version,\n                &self.manifest_digest,\n            )\n            .await?","sourceCodeStart":2500,"sourceCodeEnd":2536,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L2500-L2536","documentation":"`verify_decision_ancestry` verifies the trusted checkpoint and requires it to be at or below the decision header's height. If the decision block precedes the checkpoint, the ancestry chain between checkpoint and decision block cannot be established, so verification of the decision state is impossible and the client aborts.","triggerScenarios":"Calling the pre-sign path with a decision header (from stale swap anchors or an explicitly supplied `Verified<VerifiedBlockHeader>`) whose block number is lower than the current verified checkpoint number — typically a very old/stale anchor.","commonSituations":"Replaying a queued intent with anchors captured long ago while the checkpoint advanced; clock skew or backlog causing old headers to be used as decisions; restoring from a backup of old quote anchors.","solutions":["Re-verify/refresh the decision header (or swap anchors) so it targets a block at or after the current checkpoint.","Discard stale intents whose anchors predate the checkpoint and re-quote them.","Check for clock skew or stalled consumers that cause very old headers to be used as decision blocks.","Ensure the checkpoint source is advancing normally; a frozen checkpoint with advancing targets is fine, but old targets are not."],"exampleFix":"// before: reusing an old anchor\nlet anchors = load_stale_anchors(intent_id)?; // state.number < checkpoint.number\n// after: refresh if stale\nlet anchors = if load_stale_anchors(intent_id)?.state.number < checkpoint.number { quoter.re_anchor(intent_id).await? } else { load_stale_anchors(intent_id)? };","handlingStrategy":"validation","validationCode":"pub fn decision_after_checkpoint(decision_number: u64, checkpoint_number: u64) -> bool {\n    decision_number >= checkpoint_number\n}","typeGuard":null,"tryCatchPattern":"if decision_header.number < checkpoint.number {\n    return Err(anyhow!(\"stale decision header; re-verify before signing\"));\n}","preventionTips":["Re-anchor or re-verify decision headers instead of replaying old ones.","Drop queued intents whose anchors have been passed by the checkpoint.","Monitor consumer lag so decision headers stay near chain head."],"tags":["blockchain","checkpoint","stale-state","ancestry"],"backgroundTag":"invalid-state-transition","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}