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

  1. 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.
  2. Inspect the execution database for intents with status 'signed' before connecting and resolve them with the explicit recovery procedure documented for this client.
  3. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/933aa529c9a122e6. Report an issue: GitHub.