nautechsystems/nautilus_trader · error

Execution intent {} ({}, nonce {}) retains signer ownership

Error message

Execution intent {} ({}, nonce {}) retains signer ownership pending recovery; at most one transaction can be in flight

What it means

Raised when the single in-flight slot is occupied by an execution intent that failed or was interrupted and still retains signer ownership pending recovery (its nonce is outstanding). New transactions are blocked until the intent is recovered or finalized.

Source

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

enum TransactionAuthorization {
    Wrap {
        weth: Address,
    },
    Approve {
        token: Address,
        router: Address,
        amount: U256,
    },
}

/// The single-in-flight limit error naming the transaction currently occupying the slot.
fn in_flight_limit_error(slot: &InFlightSlot) -> anyhow::Error {
    match slot {
        InFlightSlot::Preparing(purpose) => anyhow::anyhow!(
            "A {} transaction is being prepared; at most one transaction can be in flight",
            purpose.as_str()
        ),
        InFlightSlot::Recovering(recovery) => anyhow::anyhow!(
            "Execution intent {} ({}, nonce {}) retains signer ownership pending recovery; at most one transaction can be in flight",
            recovery.intent_id,
            recovery.purpose.as_str(),
            recovery.nonce
        ),
        InFlightSlot::AwaitingFinality(in_flight) => anyhow::anyhow!(
            "Transaction {} (intent {}, {}, nonce {}) is still awaiting finality; at most one transaction can be in flight",
            in_flight.tx_hash,
            in_flight.intent_id,
            in_flight.purpose.as_str(),
            in_flight.nonce
        ),
    }
}

/// Releases a pre-signature slot claim when the slot is still in the preparing state.
///
/// Aborted or failed preparation can leave a claim behind; because no signed transaction

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Run the recovery flow for the named intent (recover by intent_id/nonce) to release signer ownership.
  2. Check the outstanding nonce's on-chain status; if the tx landed, finalize it to clear the slot.
  3. If the transaction definitively failed, cancel/replace it with the same nonce to reclaim ownership.
  4. Ensure the client's state is restored from durable storage on restart so intents aren't orphaned.

Example fix

// before: blocked by recovering intent
client.submit_order(new_order)?; // intent 0xabc... pending recovery
// after: recover first
client.recover_intent("0xabc...").await?;
client.submit_order(new_order)?;
Defensive patterns

Strategy: try-catch

Validate before calling

if let Some(slot) = client.in_flight_slot() { if slot.is_recovering() { client.recover_intent(slot.intent_id()).await?; } }

Type guard

fn is_recovering(slot: &InFlightSlot) -> bool { matches!(slot, InFlightSlot::Recovering(_)) }

Try / catch

match client.submit_order(order) { Err(e) if e.to_string().contains("pending recovery") => { let id = parse_intent_id(&e); client.recover_intent(id).await?; retry(order); } Ok(r) => r }

Prevention

When it happens

Trigger: Submitting a new transaction after a previous execution intent errored post-signing or post-submission, leaving its nonce/signer ownership in the 'Recovering' state in the InFlightSlot.

Common situations: A prior transaction's broadcast failed or its receipt was lost (RPC outage) leaving the intent pending recovery; strategy restarted mid-flight and the slot still references the old intent.

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/34bf1573da41118d. Report an issue: GitHub.