nautechsystems/nautilus_trader · error
Cannot remove strategy, {strategy_id} not found
Error message
Cannot remove strategy, {strategy_id} not found What it means
remove_strategy is a guard-clause in Trader::remove_strategy: it checks strategy_ids membership and bails if the StrategyId was never registered (or was already removed). The trader refuses to remove an unknown strategy rather than silently succeeding.
Source
Thrown at crates/system/src/trader.rs:1424
};
Ok(handler)
}
/// Removes the strategy with the given `strategy_id`.
///
/// Will stop the strategy first if it is currently running. Disposes the strategy
/// and removes it from the trader's tracking along with its event subscriptions.
///
/// # Errors
///
/// Returns an error if the strategy is not registered, the cache is already borrowed, or
/// disposal fails. A cache borrow failure preserves the strategy registration and its external
/// order claims. A failed disposal keeps the strategy registered and tracked, and leaves it
/// `Faulted`; see [`Component::dispose`]. Calling this again retires the strategy.
pub fn remove_strategy(&mut self, strategy_id: &StrategyId) -> anyhow::Result<()> {
if !self.strategy_ids.contains(strategy_id) {
anyhow::bail!("Cannot remove strategy, {strategy_id} not found");
}
// Stop if running, then dispose
let _ = stop_component(&strategy_id.inner());
self.retire_strategy(*strategy_id)?;
log::info!(
"Removed strategy {strategy_id} from trader {}",
self.trader_id
);
Ok(())
}
/// Disposes an actor, then releases everything its registration created.
///
/// Each component is retired completely before the next one starts, so a failure part way
/// through a bulk operation leaves the trader's bookkeeping consistent with the registries.
fn retire_actor(&mut self, actor_id: ActorId) -> anyhow::Result<()> {View on GitHub (pinned to 18893faf8b)
Solutions
- Check trader.strategy_ids().contains(strategy_id) before calling remove_strategy
- Ensure the strategy was registered via trader.add_strategy before removal
- Track removal state so teardown logic doesn't call remove_strategy twice
- Log the registered strategy IDs when the removal fails to spot ID mismatches
Example fix
// before
trader.remove_strategy(&strategy_id)?;
// after
if trader.strategy_ids().contains(&strategy_id) {
trader.remove_strategy(&strategy_id)?;
} Defensive patterns
Strategy: validation
Validate before calling
if trader.strategy_ids().contains(&strategy_id) { trader.remove_strategy(&strategy_id)?; } Try / catch
match trader.remove_strategy(&id) { Err(e) if e.to_string().contains("not found") => {/* already removed */}, other => other?, } Prevention
- Track removal state to avoid double teardown
- Only remove strategies you added and hold IDs for
When it happens
Trigger: Calling trader.remove_strategy(&strategy_id) with an ID that was never added, a strategy already removed in a prior call, or an ID from a different trader/config.
Common situations: Double teardown during shutdown; config lists a strategy that failed to register at startup; ID constructed manually instead of taken from the trader's registry.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Trader cannot register with itself
- Active execution intent {intent_id} was not found
- DataActor {} must be registered before calling `clock_mut()`
- DataActor {} must be registered before calling `clock()` - t
- DataActor {} must be registered before calling `clock_ref()`
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/77e0a36e510559a2.
Report an issue: GitHub.