nautechsystems/nautilus_trader · error
Execution intent {} has a signed transaction {} that was not
Error message
Execution intent {} has a signed transaction {} that was not authorized for broadcast; its nonce remains reserved pending explicit recovery What it means
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.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:1266
current_payload = Some(raw_transaction);
}
}
anyhow::ensure!(
!authenticated_payloads.is_empty(),
"Execution intent {} has no persisted signed transaction bytes",
intent.id
);
if intent.status == "broadcast" {
anyhow::ensure!(
current_payload.is_some(),
"Broadcast execution intent {} has no persisted signed transaction bytes",
intent.id
);
}
if intent.status == "signed" {
anyhow::bail!(
"Execution intent {} has a signed transaction {} that was not authorized for broadcast; its nonce remains reserved pending explicit recovery",
intent.id,
tx_hash
);
}
*self.in_flight.lock() = Some(InFlightSlot::AwaitingFinality(InFlightTransaction {
intent_id: intent.id,
nonce,
tx_hash,
purpose,
}));
let plan = if purpose == TransactionPurpose::Swap {
Some(self.restore_swap_plan(&intent)?)
} else {
None
};View on GitHub (pinned to 18893faf8b)
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.
Example fix
// before: connect() fails on the reserved signed intent
client.connect().await?;
// after: explicitly recover or discard the signed intent first
let signed = db.intents_with_status("signed").await?;
for intent in signed {
recovery_client.resolve_signed_intent(intent.id).await?; // broadcast or void + release nonce
}
client.connect().await?; Defensive patterns
Strategy: validation
Validate before calling
// Before connect(), ensure no intents remain in the signed state
let pending = db.intents_with_status("signed").await?;
if !pending.is_empty() {
// run the explicit recovery flow for each intent, then retry connect
} Type guard
fn is_reconcilable(intent: &ExecutionIntentRow) -> bool {
intent.status != "signed"
} Try / catch
// catch and surface, never auto-broadcast on reconnect
match client.connect().await {
Err(e) if e.to_string().contains("not authorized for broadcast") => {
log::error!("signed intent awaiting explicit recovery: {e}");
// page operator / run recovery procedure
}
result => result?,
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- A recoverable execution for wallet {} retains signed transac
- Active execution intent {} has no nonce
- Canonical head changed during signer-nonce replacement scan
- Verified finalized transaction count advanced without an act
- Canonical nonce advanced without an authenticated signer tra
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/933aa529c9a122e6.
Report an issue: GitHub.