nautechsystems/nautilus_trader · error

Invalid `strategy_id` type

Error message

Invalid `strategy_id` type

What it means

configure_py_strategy extracts the `strategy_id` attribute from the Python strategy config object. It accepts a StrategyId or a string convertible via StrategyId::new_checked; any other Python type fails extraction and triggers this bail. It is a strict argument-type guard during strategy configuration.

Source

Thrown at crates/system/src/python/registration.rs:662

        .call_method("loads", (json_str,), None)?
        .into_any())
}

fn configure_py_strategy(
    strategy: &mut PyRefMut<'_, PyStrategy>,
    config_obj: &Bound<'_, PyAny>,
) -> anyhow::Result<()> {
    if let Some(strategy_id) = config_obj
        .getattr("strategy_id")
        .ok()
        .filter(|value| !value.is_none())
    {
        let strategy_id = if let Ok(strategy_id) = strategy_id.extract::<StrategyId>() {
            strategy_id
        } else if let Ok(strategy_id_str) = strategy_id.extract::<String>() {
            StrategyId::new_checked(&strategy_id_str)?
        } else {
            anyhow::bail!("Invalid `strategy_id` type");
        };
        strategy.set_strategy_id(strategy_id)?;
    }

    if let Some(order_id_tag) = config_obj
        .getattr("order_id_tag")
        .ok()
        .filter(|value| !value.is_none())
    {
        let order_id_tag = order_id_tag
            .extract::<String>()
            .map_err(|e| anyhow::anyhow!("Invalid `order_id_tag` type: {e}"))?;
        strategy.set_order_id_tag(&order_id_tag)?;
    }

    if let Some(log_events) = extract_bool_config_attr(config_obj, "log_events") {
        strategy.set_log_events(log_events);
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set `strategy_id` on the config to a valid string like "MyStrategy-001" or a StrategyId instance.
  2. Wrap plain strings with StrategyId before assignment if constructing in Python.
  3. Check the config isn't passing None because of an unset dataclass field.

Example fix

// before
config = MyStrategyConfig(strategy_id=123)
// after
config = MyStrategyConfig(strategy_id="MyStrategy-001")
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(config.strategy_id, (str, StrategyId)):
    raise TypeError("config.strategy_id must be a StrategyId or string")

Type guard

def has_valid_strategy_id(config) -> bool:
    sid = getattr(config, "strategy_id", None)
    return isinstance(sid, str) and sid or isinstance(sid, StrategyId)

Try / catch

try:
    trader.add_strategy(strategy)
except Exception as e:
    if "Invalid `strategy_id` type" in str(e):
        raise ValueError("Set config.strategy_id to a 'Name-001' string") from e
    raise

Prevention

When it happens

Trigger: Passing a strategy config whose `strategy_id` attribute is None, an int, a different domain object (e.g. InstrumentId), or an invalid identifier string that even new_checked would have rejected earlier.

Common situations: Forgetting to set strategy_id on the config, assigning a raw int/enum, or copying an id object of the wrong type from another component.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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