nautechsystems/nautilus_trader · error · anyhow::Error

Invalid config type for AxExecutionClientFactory. Expected A

Error message

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

What it means

AxExecutionClientFactory::create downcasts the provided &dyn ClientConfig to AxExecClientConfig and bails when the concrete type differs, printing the actual value. As with the data factory, this arises only from manual factory wiring or a custom FactoryRouter - the normal TradingNode routing always supplies the matching config type (AxExecClientConfig, which also carries trader_id and account settings).

Source

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

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

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

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

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

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Pass an AxExecClientConfig to AxExecutionClientFactory::create
  2. Prefer TradingNode + routing config so Nautilus pairs factories with their configs for you
  3. Inspect the {config:?} in the message to identify which object was actually passed

Example fix

# Python, before
exec_client = AxExecutionClientFactory().create(
    sweep(data_config)   # wrong class
)
# after
exec_config = AxExecClientConfig()
exec_client = AxExecutionClientFactory().create(
    sweep(exec_config)
)
Defensive patterns

Strategy: type-guard

Type guard

// Rust
fn is_ax_exec_config(cfg: &dyn ClientConfig) -> bool {
    cfg.as_any().downcast_ref::<AxExecClientConfig>().is_some()
}
# Python
isinstance(config, AxExecClientConfig)

Try / catch

match AxExecutionClientFactory.create(name, config, cache) {
    Err(e) if e.to_string().contains("Invalid config type") => {
        return Err(e.context("passed wrong config to AxExecutionClientFactory; expected AxExecClientConfig"));
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling the execution factory's create with AxDataClientConfig, another adapter's config, or a bespoke ClientConfig impl; swapping data/exec configs in hand-written wiring; Python-side passing the wrong nautilus_trader.adapters.architect_ax config class.

Common situations: Custom backtest/live harnesses that build clients by hand; refactors that moved factory registration into generic code; copy-paste of a working Binance/Bybit wiring block with configs not renamed.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/d3b7ae9e4b668532. Report an issue: GitHub.