nautechsystems/nautilus_trader · critical

A recoverable execution for wallet {} retains signed transac

Error message

A recoverable execution for wallet {} retains signed transaction bytes; refusing to reuse its nonce without explicit recovery

What it means

During startup reconciliation, the client refuses to acquire a nonce when the database still holds a recoverable execution containing signed transaction bytes for this wallet. Reusing the nonce could broadcast a second transaction with the same nonce, so recovery must be explicit. This is a safety interlock against double-spend / nonce-collision from an interrupted broadcast.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:1134

            amount_in,
            min_amount_out: U256::ZERO,
            slippage_bps: 0,
            quote_spend_ceiling: None,
            profiler_position: None,
        })
    }

    async fn reconcile_unresolved_execution(&self) -> anyhow::Result<()> {
        let database = self.cache.database.clone().ok_or_else(|| {
            anyhow::anyhow!("No durable store configured for execution reconciliation")
        })?;
        let _payload_lease = database
            .acquire_execution_payload_lease(self.payload_keys.as_deref().ok_or_else(|| {
                anyhow::anyhow!("Protected payload keys are required for execution recovery")
            })?)
            .await?;
        let wallet_address = self.wallet_address.to_string();
        anyhow::ensure!(
            !database
                .has_recoverable_signed_execution(self.chain.chain_id, &wallet_address)
                .await?,
            "A recoverable execution for wallet {} retains signed transaction bytes; refusing to reuse its nonce without explicit recovery",
            self.wallet_address
        );
        let Some(intent) = database
            .get_active_execution_intent(self.chain.chain_id, &wallet_address)
            .await?
        else {
            return Ok(());
        };
        anyhow::ensure!(
            intent.schema_version == crate::execution::transaction::EXECUTION_SCHEMA_VERSION,
            "Execution intent {} uses unsupported schema version {}",
            intent.id,
            intent.schema_version
        );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Run the explicit recovery flow (recovery path of reconcile_unresolved_execution / recovery tooling) to replay or discard the stored signed execution before reconnecting
  2. Clear the recoverable signed execution rows for this wallet in the execution database once the transaction's on-chain status is confirmed
  3. Ensure only one client instance uses this wallet/keystore at a time and that previous runs shut down cleanly
  4. Restore the payload keys (payload_keys config) so recovery can proceed instead of failing earlier
Defensive patterns

Strategy: validation

Validate before calling

// before connect(), check recovery state
let has_recoverable = database.has_recoverable_signed_execution(chain.chain_id, &wallet_address).await?;
if has_recoverable {
    // run explicit recovery or clean the rows first
}

Prevention

When it happens

Trigger: connect() calls reconcile_unresolved_execution(); database.has_recoverable_signed_execution(chain_id, wallet) returns true because a previous run persisted signed tx bytes (raw/sealed transaction) for a wallet before crashing or being killed mid-broadcast.

Common situations: Process killed after signing but before confirming broadcast; crash during deployment; running a second instance against the same wallet/database; stale recovery rows left after an aborted run.

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/80a4c2c621cc63fd. Report an issue: GitHub.