{"record":{"id":"d3ce414524233c4c","repo":"nautechsystems/nautilus_trader","slug":"failed-to-mark-execution-intent-replaced-e","errorCode":null,"errorMessage":"Failed to mark execution intent replaced: {e}","messagePattern":"Failed to mark execution intent replaced: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3848,"sourceCode":"            \",\n        )\n        .bind(intent_id)\n        .bind(chain_id_db)\n        .bind(transaction_hash)\n        .fetch_optional(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to persist replacement hash {transaction_hash}: {e}\"))?\n        .ok_or_else(|| {\n            anyhow::anyhow!(\"Replacement hash {transaction_hash} conflicts with another intent\")\n        })?;\n\n        sqlx::query(\n            \"UPDATE execution_intent SET status = 'replaced', updated_at = NOW() WHERE id = $1\",\n        )\n        .bind(intent_id)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to mark execution intent replaced: {e}\"))?;\n        sqlx::query(\n            \"\n            INSERT INTO execution_transaction_transition (\n                intent_id, transaction_hash_id, transition_key, from_status, to_status\n            ) VALUES ($1, $2, $3, $4, 'replaced')\n            ON CONFLICT (intent_id, transition_key) DO NOTHING\n            \",\n        )\n        .bind(intent_id)\n        .bind(row.id)\n        .bind(format!(\"replaced:{transaction_hash}\"))\n        .bind(current_status)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to record replacement transition: {e}\"))?;\n\n        transaction\n            .commit()","sourceCodeStart":3830,"sourceCodeEnd":3866,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3830-L3866","documentation":"Wrapped sqlx error from the UPDATE execution_intent SET status = 'replaced', updated_at = NOW() WHERE id = $1 statement in add_execution_replacement_hash (database.rs:3842-3849). At this point the intent row is already locked FOR UPDATE and the replacement hash row was persisted, so a failure here rolls the whole replacement recording back. Typical causes are connection loss, timeouts, or a constraint on the status column rejecting 'replaced'.","triggerScenarios":"Connection dropping mid-transaction after the upsert; a CHECK/domain on execution_intent.status that does not include 'replaced' (schema older than replacement support); statement_timeout or serialization abort hitting at this statement.","commonSituations":"Schema migrated only partially when replacement support landed; Postgres failover during replacement processing; very tight statement_timeout with the FOR UPDATE lock held through several statements.","solutions":["Downcast to sqlx::Error to distinguish constraint faults from connectivity faults","Widen any status CHECK constraint to include 'replaced' via a migration if that is the reported cause","Retry the full add_execution_replacement_hash call on transient classes; the rollback makes the retry idempotent (the 'replaced:{hash}' transition key dedupes)","Keep the transaction short to reduce the lock-held window and timeout exposure"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_transient_db_error(err: &anyhow::Error) -> bool {\n    err.downcast_ref::<sqlx::Error>().map_or(false, |e| {\n        matches!(e, sqlx::Error::PoolTimedOut | sqlx::Error::PoolClosed | sqlx::Error::Io(_))\n            || e.as_database_error().and_then(|d| d.code()).map_or(false, |c| {\n                matches!(c.as_ref(), \"40001\" | \"40P01\" | \"55P03\" | \"57014\" | \"08000\" | \"08003\" | \"08006\")\n            })\n    })\n}","tryCatchPattern":"match db.add_execution_replacement_hash(intent_id, chain_id, &hash).await {\n    Ok(row) => Ok(row),\n    Err(e) if is_transient_db_error(&e) => retry_with_backoff(e),\n    Err(e) => Err(e),\n}","preventionTips":["Keep status CHECK constraints in execution_intent in sync with the TransactionStatus set","Apply replacement-support migrations before deploying code that records replacements","Short transactions again: this statement runs late in the flow, so lock-held time is the risk"],"tags":["rust","sqlx","postgres","blockchain","transaction","replacement"],"backgroundTag":"database-update-failed","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}