{"record":{"id":"933aa529c9a122e6","repo":"nautechsystems/nautilus_trader","slug":"execution-intent-has-a-signed-transaction-th","errorCode":null,"errorMessage":"Execution intent {} has a signed transaction {} that was not authorized for broadcast; its nonce remains reserved pending explicit recovery","messagePattern":"Execution intent (.+?) has a signed transaction (.+?) that was not authorized for broadcast; its nonce remains reserved pending explicit recovery","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1266,"sourceCode":"                current_payload = Some(raw_transaction);\n            }\n        }\n        anyhow::ensure!(\n            !authenticated_payloads.is_empty(),\n            \"Execution intent {} has no persisted signed transaction bytes\",\n            intent.id\n        );\n\n        if intent.status == \"broadcast\" {\n            anyhow::ensure!(\n                current_payload.is_some(),\n                \"Broadcast execution intent {} has no persisted signed transaction bytes\",\n                intent.id\n            );\n        }\n\n        if intent.status == \"signed\" {\n            anyhow::bail!(\n                \"Execution intent {} has a signed transaction {} that was not authorized for broadcast; its nonce remains reserved pending explicit recovery\",\n                intent.id,\n                tx_hash\n            );\n        }\n\n        *self.in_flight.lock() = Some(InFlightSlot::AwaitingFinality(InFlightTransaction {\n            intent_id: intent.id,\n            nonce,\n            tx_hash,\n            purpose,\n        }));\n\n        let plan = if purpose == TransactionPurpose::Swap {\n            Some(self.restore_swap_plan(&intent)?)\n        } else {\n            None\n        };","sourceCodeStart":1248,"sourceCodeEnd":1284,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L1248-L1284","documentation":"During reconnect, reconcile_unresolved_execution() replays persisted execution intents. If an intent is still in the 'signed' status — a transaction was signed and persisted but never authorized for broadcast — the client refuses to proceed and fails connect, because broadcasting it here would be an implicit authorization and its nonce must remain reserved. Recovery must be done explicitly by an operator.","triggerScenarios":"Calling connect() while the execution database contains an intent with status == \"signed\" (signed bytes persisted, never marked broadcast). This happens when a previous run crashed or was shut down between signing and broadcast authorization.","commonSituations":"Process crash or kill after sign-and-persist but before broadcast; deploy/rollback mid-transaction; operator intentionally halted a signed-but-unsent transaction and then restarted the client; database replay after a failed broadcast attempt that never transitioned the status.","solutions":["Explicitly recover the intent out-of-band: decide to broadcast the signed transaction (through the designated recovery/broadcast path) or discard it and release the nonce, updating the intent status accordingly.","Inspect the execution database for intents with status 'signed' before connecting and resolve them with the explicit recovery procedure documented for this client.","If the signed transaction is stale (e.g. nonce expired, gas price obsolete), replace or void it via the recovery flow so the reserved nonce is freed before reconnecting."],"exampleFix":"// before: connect() fails on the reserved signed intent\nclient.connect().await?;\n\n// after: explicitly recover or discard the signed intent first\nlet signed = db.intents_with_status(\"signed\").await?;\nfor intent in signed {\n    recovery_client.resolve_signed_intent(intent.id).await?; // broadcast or void + release nonce\n}\nclient.connect().await?;","handlingStrategy":"validation","validationCode":"// Before connect(), ensure no intents remain in the signed state\nlet pending = db.intents_with_status(\"signed\").await?;\nif !pending.is_empty() {\n    // run the explicit recovery flow for each intent, then retry connect\n}","typeGuard":"fn is_reconcilable(intent: &ExecutionIntentRow) -> bool {\n    intent.status != \"signed\"\n}","tryCatchPattern":"// catch and surface, never auto-broadcast on reconnect\nmatch client.connect().await {\n    Err(e) if e.to_string().contains(\"not authorized for broadcast\") => {\n        log::error!(\"signed intent awaiting explicit recovery: {e}\");\n        // page operator / run recovery procedure\n    }\n    result => result?,\n}","preventionTips":["Always run the explicit signed-transaction recovery procedure after any abnormal shutdown before reconnecting.","Monitor the execution database for status 'signed' rows with an alert.","Gracefully stop the execution client (allowing sign→broadcast to complete or be rolled back) instead of killing the process mid-lifecycle."],"tags":["blockchain","nonce","recovery","transaction-broadcast"],"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-14T05:17:10.506Z"}