nautechsystems/nautilus_trader · error

Invalid config type for AxExecutionClientFactory. Expected A

Error message

Invalid config type for AxExecutionClientFactory. Expected AxExecutionClientConfig, was {config:?}

What it means

AxExecutionClientFactory::create downcasts the generic config to `AxExecutionClientConfig`; any other config type causes this error, echoing the received config's debug output. Like its data-client sibling, it is a factory type guard.

Source

Thrown at crates/adapters/architect_ax/src/factories.rs:204

impl Default for AxExecutionClientFactory {
    fn default() -> Self {
        Self::new()
    }
}

impl ExecutionClientFactory for AxExecutionClientFactory {
    fn create(
        &self,
        trader_id: TraderId,
        name: &str,
        config: &dyn ClientConfig,
        cache: CacheView,
    ) -> anyhow::Result<Box<dyn ExecutionClient>> {
        let ax_config = config
            .as_any()
            .downcast_ref::<AxExecutionClientConfig>()
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "Invalid config type for AxExecutionClientFactory. Expected AxExecutionClientConfig, was {config:?}",
                )
            })?
            .clone();

        // AX uses netting for perpetual futures
        let oms_type = OmsType::Netting;
        let account_type = AccountType::Margin;

        let core = ExecutionClientCore::new(
            trader_id,
            ClientId::from(name),
            *AX_VENUE,
            oms_type,
            ax_config.account_id,
            account_type,
            None, // base_currency
            cache,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass an `AxExecutionClientConfig` to the execution factory.
  2. Check the `{config:?}` text in the message to identify the wrongly passed type.
  3. Ensure each venue config block is routed to its matching factory (data config -> data factory, execution config -> execution factory).
  4. If using a builder/generic loader, add explicit per-factory config construction instead of reusing one struct.

Example fix

// before
let exec_config = AxDataClientConfig { ... };
factory.create(name, exec_config, ...)?; // wrong type

// after
let exec_config = AxExecutionClientConfig {
    api_key: Some(api_key),
    api_secret: Some(api_secret),
    ..Default::default()
};
factory.create(name, exec_config, ...)?;
Defensive patterns

Strategy: type-guard

Validate before calling

// before calling the execution factory
let Some(_) = config.as_any().downcast_ref::<AxExecutionClientConfig>() else {
    panic!("config passed to AxExecutionClientFactory must be AxExecutionClientConfig");
};

Type guard

fn as_ax_exec_config(config: &dyn Any) -> Option<&AxExecutionClientConfig> {
    config.downcast_ref::<AxExecutionClientConfig>()
}

Try / catch

match factory.create(name, config, cache, ...) {
    Err(e) if e.to_string().contains("Invalid config type for AxExecutionClientFactory") => {
        return Err(anyhow::anyhow!("pass AxExecutionClientConfig to the execution factory: {e}"));
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling `AxExecutionClientFactory.create(name, config, ...)` with a config that is not `AxExecutionClientConfig` — commonly an `AxDataClientConfig` or a generic/other-venue execution config.

Common situations: Swapping data/execution configs in a multi-adapter bootstrap; passing a shared base config struct; registering the AX execution factory under a name whose config block belongs to the data client.

Related errors


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