{"record":{"id":"19007054cd14d367","repo":"nautechsystems/nautilus_trader","slug":"intent-cannot-attach-a-verified-replacement-from-s","errorCode":null,"errorMessage":"Intent cannot attach a verified replacement from status {current_status}","messagePattern":"Intent cannot attach a verified replacement from status (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6421,"sourceCode":"            .bind(nonce)\n            .bind(decision.read_class)\n            .bind(height_start)\n            .bind(height_end)\n            .bind(scan.manifest_version)\n            .bind(scan.manifest_digest)\n            .bind(scan.provider_ids)\n            .bind(scan.operator_ids)\n            .bind(scan.failure_domain_ids)\n            .bind(&decision.normalized_value_digest)\n            .bind(revision)\n            .bind(transition_key)\n            .execute(&mut *transaction)\n            .await\n            .context(\"failed to persist replacement scan evidence\")?;\n        }\n\n        if let Some(transaction_hash) = scan.matched_transaction_hash {\n            anyhow::ensure!(\n                execution_transition_allowed(&current_status, TransactionStatus::Replaced),\n                \"Intent cannot attach a verified replacement from status {current_status}\"\n            );\n            let (hash_id, payload_expected, already_current) =\n                sqlx::query_as::<_, (i64, bool, bool)>(\n                    \"\n                    SELECT id, payload_expected, current\n                    FROM execution_transaction_hash\n                    WHERE intent_id = $1 AND chain_id = $2 AND transaction_hash = $3\n                    FOR UPDATE\n                    \",\n                )\n                .bind(scan.intent_id)\n                .bind(chain_id)\n                .bind(transaction_hash)\n                .fetch_optional(&mut *transaction)\n                .await\n                .context(\"failed to lock authenticated replacement payload\")?","sourceCodeStart":6403,"sourceCodeEnd":6439,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6403-L6439","documentation":"When the scan found a replacement transaction hash, the intent's current status must permit the transition to `Replaced` per `execution_transition_allowed`. If the intent is in a status from which `Replaced` is illegal (e.g. already `replaced`, `failed`, or beyond the attachable lifecycle stage), the evidence cannot be attached and the transaction fails with the offending status embedded in the message.","triggerScenarios":"Calling `record_execution_replacement_scan` with `matched_transaction_hash = Some(..)` while the locked intent's `status` is one for which `execution_transition_allowed(current_status, TransactionStatus::Replaced)` returns false — e.g. an already-`replaced` intent receiving a second replacement, or a `failed`/terminal-state intent.","commonSituations":"A duplicate scan re-attached a replacement after the first already transitioned the intent; the intent failed for another reason between scan start and commit; lifecycle stages were run out of order by the caller.","solutions":["Check the intent's current status before attaching a replacement; skip the attach step if it already equals `replaced`.","Do not attach a replacement hash to intents in terminal states; record the finding elsewhere or open a new intent.","Ensure scan steps run in the lifecycle order the state machine expects."],"exampleFix":"// before\nif let Some(tx_hash) = scan.matched_transaction_hash { db.record_execution_replacement_scan(&scan).await?; }\n// after\nif let Some(_) = scan.matched_transaction_hash {\n    if db.execution_intent_status(scan.intent_id).await? == \"replaced\" { return Ok(()); } // already handled\n}\ndb.record_execution_replacement_scan(&scan).await?;","handlingStrategy":"validation","validationCode":"let status = sqlx::query_scalar::<_, String>(\"SELECT status FROM execution_intent WHERE id=$1\").bind(scan.intent_id).fetch_optional(&pool).await?;\nif let Some(s) = status {\n    if s == \"replaced\" { return Ok(()); } // already transitioned\n    if !matches!(s.as_str(), \"prepared\" | \"pending\") { return Err(anyhow!(\"status {s} cannot attach a replacement\")); }\n}","typeGuard":"fn can_attach_replacement(status: &str) -> bool { matches!(status, \"prepared\" | \"pending\") }","tryCatchPattern":"match db.record_execution_replacement_scan(&scan).await {\n    Err(e) if e.to_string().starts_with(\"Intent cannot attach a verified replacement from status\") => warn!(\"intent already advanced past attachable stage; skipping\"),\n    Err(e) => return Err(e),\n    Ok(()) => {},\n}","preventionTips":["Read the intent status immediately before submitting a scan with a matched replacement.","Idempotently skip scans for intents already in the `replaced` state.","Keep the intent lifecycle single-threaded per intent so intermediate states cannot be missed."],"tags":["state-machine","database","consistency"],"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"}