nautechsystems/nautilus_trader · error

Invalid config type for OKXExecutionClientFactory. Expected

Error message

Invalid config type for OKXExecutionClientFactory. Expected OKXExecutionClientConfig, was {config:?}

What it means

OKXExecutionClientFactory::create only accepts configs downcastable to OKXExecutionClientConfig. Any other config type fails the downcast and produces this error with the offending config's debug dump. This guards against wiring a non-OKX execution config into the OKX factory.

Source

Thrown at crates/adapters/okx/src/factories.rs:150

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

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

        let has_derivatives = okx_config.instrument_types.iter().any(|t| {
            matches!(
                t,
                OKXInstrumentType::Swap | OKXInstrumentType::Futures | OKXInstrumentType::Option
            )
        });

        let account_type = if okx_config.use_spot_margin || has_derivatives {
            AccountType::Margin
        } else {
            AccountType::Cash
        };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Construct the config as OKXExecutionClientConfig including instrument_types and required credentials.
  2. Verify the execution factory registration pairs the OKX factory with the OKX config type.
  3. Correct the config serialization so the concrete type resolves to OKXExecutionClientConfig.

Example fix

// before
let cfg = ExecutionClientConfig::default(); factory.create(name, cfg, clock, cache)
// after
let cfg = OKXExecutionClientConfig::new(...).with_instrument_types(vec![OKXInstrumentType::Spot]);
factory.create(name, Box::new(cfg), clock, cache);
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_okx_exec_config(cfg: &dyn ClientConfig) -> bool {
    cfg.as_any().downcast_ref::<OKXExecutionClientConfig>().is_some()
}

Type guard

fn as_okx_exec_config(cfg: &dyn ClientConfig) -> Option<&OKXExecutionClientConfig> {
    cfg.as_any().downcast_ref::<OKXExecutionClientConfig>()
}

Try / catch

match as_okx_exec_config(config.as_ref()) {
    Some(okx_cfg) => factory.create(name, config, clock, cache),
    None => return Err(anyhow!("expected OKXExecutionClientConfig, got {config:?}")),
}

Prevention

When it happens

Trigger: Calling OKXExecutionClientFactory::create with a config that is not OKXExecutionClientConfig, such as another venue's ExecutionClientConfig or a wrongly-typed deserialized config.

Common situations: Copy-pasting factory wiring across adapters; config files where the execution client section specifies the wrong type; multi-venue setups with mismatched factory/config registration.

Related errors


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