nautechsystems/nautilus_trader · error

Invalid config type for OKXDataClientFactory. Expected OKXDa

Error message

Invalid config type for OKXDataClientFactory. Expected OKXDataClientConfig, was {config:?}

What it means

OKXDataClientFactory::create only accepts a config object that downcasts to OKXDataClientConfig. When the registered config type differs (wrong adapter config passed to the factory), the downcast fails and the factory refuses to construct a data client, echoing the actual config's debug representation.

Source

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

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

impl DataClientFactory for OKXDataClientFactory {
    fn create(
        &self,
        name: &str,
        config: &dyn ClientConfig,
        _cache: CacheView,
        _clock: Rc<RefCell<dyn Clock>>,
    ) -> anyhow::Result<Box<dyn DataClient>> {
        let okx_config = config
            .as_any()
            .downcast_ref::<OKXDataClientConfig>()
            .ok_or_else(|| {
                anyhow::anyhow!(
                    "Invalid config type for OKXDataClientFactory. Expected OKXDataClientConfig, was {config:?}",
                )
            })?
            .clone();

        let client_id = ClientId::from(name);
        let client = OKXDataClient::new(client_id, okx_config)?;
        Ok(Box::new(client))
    }

    fn name(&self) -> &'static str {
        OKX
    }

    fn config_type(&self) -> &'static str {
        "OKXDataClientConfig"
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the config passed for client name is constructed as OKXDataClientConfig (or deserialized into it).
  2. Check the trader's client registration map so each factory name maps to the matching OKX config type.
  3. Fix the config file/serialization so the concrete type tag identifies OKXDataClientConfig.

Example fix

// before
let config = DataClientConfig::new(...) ; factory.create(name, config.boxed(), ...)
// after
let config = OKXDataClientConfig::new(api_key, api_secret, passphrase);
factory.create(name, Box::new(config), ...);
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Calling OKXDataClientFactory::create with a ClientConfig that is not OKXDataClientConfig, e.g. a BinanceDataClientConfig, generic DataClientConfig, or deserialized config whose concrete type was lost.

Common situations: Mixing adapter configs when running multiple venues; loading client configs from JSON/TOML where the type tag is wrong; renaming or refactoring config structs across versions.

Related errors


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