nautechsystems/nautilus_trader · error

{e}; failed to roll back external order claims for {strategy

Error message

{e}; failed to roll back external order claims for {strategy_id}: {rollback_error}

What it means

In `add_strategy`, when creating the exec engine fails, the node tries to roll back external order claims registered for the strategy's instrument IDs. If that rollback also fails, the original error is augmented with the rollback failure via `anyhow::bail!` so both causes are visible. This preserves the original failure context while surfacing that cleanup could not complete, meaning external order claims may be left dangling.

Source

Thrown at crates/live/src/node/mod.rs:2732

            self.register_external_order_claims(strategy_id, &instrument_ids)?;
        }

        let mut exec_engine = match oms_type
            .map(|_| {
                self.kernel
                    .exec_engine
                    .try_borrow_mut()
                    .map_err(|e| anyhow::anyhow!("Cannot register OMS type: {e}"))
            })
            .transpose()
        {
            Ok(exec_engine) => exec_engine,
            Err(e) => {
                if !instrument_ids.is_empty()
                    && let Err(rollback_error) =
                        self.rollback_external_order_claims(strategy_id, &instrument_ids)
                {
                    anyhow::bail!(
                        "{e}; failed to roll back external order claims for {strategy_id}: {rollback_error}"
                    );
                }
                return Err(e);
            }
        };

        if let Err(add_error) = self.kernel.trader.borrow_mut().add_strategy(strategy) {
            drop(exec_engine);

            if !instrument_ids.is_empty()
                && let Err(rollback_error) =
                    self.rollback_external_order_claims(strategy_id, &instrument_ids)
            {
                anyhow::bail!(
                    "Failed to add strategy {strategy_id}: {add_error}; failed to roll back external order claims: {rollback_error}"
                );
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Fix the root cause reported in the leading `{e}` part of the message (exec engine creation failure) first.
  2. Inspect why rollback failed (trailing `{rollback_error}`): verify the cache/backing store used by external order claims is reachable and consistent.
  3. Restart the node to clear any stale in-memory claim state, then re-add the strategy.
  4. Check that instrument_ids passed to add_strategy are valid and that no concurrent add_strategy call is mutating the same claims.

Example fix

// before: rollback failure is opaque
anyhow::bail!("{e}; failed to roll back external order claims for {strategy_id}: {rollback_error}");
// after: caller ensures node is idle and cache healthy before adding
assert_eq!(node.state(), NodeState::Idle);
node.connect_cache()?; // ensure backing cache reachable
node.add_strategy(strategy)?;
Defensive patterns

Strategy: try-catch

Validate before calling

if node.state() != NodeState::Idle {
    anyhow::bail!("node must be idle before add_strategy");
}

Type guard

fn can_add(node: &LiveNode) -> bool { node.state() == NodeState::Idle }

Try / catch

match node.add_strategy(strategy) {
    Err(e) if e.to_string().contains("failed to roll back external order claims") => {
        // both engine creation and rollback failed: inspect inner rollback_error, restart node
    }
    Err(e) => return Err(e),
    Ok(_) => {}
}

Prevention

When it happens

Trigger: Calling `add_strategy` where exec engine creation returns `Err(e)` AND `instrument_ids` is non-empty AND `rollback_external_order_claims` itself returns `Err(rollback_error)` (e.g. claim records missing, cache lock poisoned, or a persistence/redis failure during claim removal).

Common situations: A misconfigured strategy or unavailable data/exec client causes engine creation to fail, while the rollback path independently fails due to a broken cache/redis connection or the claims having already been partially removed by a previous failed attempt.

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