nautechsystems/nautilus_trader · error

Invalid config type for DeriveExecutionClientFactory. Expect

Error message

Invalid config type for DeriveExecutionClientFactory. Expected DeriveExecutionClientConfig, was {config:?}

What it means

The DeriveExecutionClientFactory only accepts a config object that is (or wraps) a DeriveExecutionClientConfig. When downcasting the generic config fails, it throws this anyhow error naming the actual config type that was passed. It guards against wiring a client factory with the wrong adapter's config.

Source

Thrown at crates/adapters/derive/src/factories.rs:144

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

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

        // Derive perpetuals net per-subaccount; cash accounts are spot.
        let oms_type = OmsType::Netting;
        let account_type = AccountType::Margin;

        let core = ExecutionClientCore::new(
            trader_id,
            ClientId::from(name),
            *DERIVE_VENUE,
            oms_type,
            derive_config.account_id,
            account_type,
            None,
            cache,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass a DeriveExecutionClientConfig instance to the factory's create call
  2. Check that the config being constructed for this venue is the execution config, not the data config
  3. If building configs dynamically, match on the variant and dispatch to the matching factory

Example fix

// before
let client = exec_factory.create(config, cache)?; // config is DeriveDataClientConfig
// after
let exec_config = DeriveExecutionClientConfig::new(trader_id, account_id, ...);
let client = exec_factory.create(Box::new(exec_config), cache)?;
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_derive_exec_config(config: &dyn ClientConfig) -> bool { config.as_any().downcast_ref::<DeriveExecutionClientConfig>().is_some() }

Type guard

fn as_derive_exec_config(config: &dyn ClientConfig) -> Option<&DeriveExecutionClientConfig> { config.as_any().downcast_ref::<DeriveExecutionClientConfig>() }

Try / catch

match as_derive_exec_config(config.as_ref()) { Some(c) => build(c), None => return Err(anyhow!("expected DeriveExecutionClientConfig, check factory wiring")) }

Prevention

When it happens

Trigger: Calling DeriveExecutionClientFactory::create with any config whose downcast_ref::<DeriveExecutionClientConfig>() returns None — e.g. a DeriveDataClientConfig, another exchange's ExecutionClientConfig, or a generically-built config.

Common situations: Copy-pasted factory wiring where the data-client config is reused for the exec client; building configs from TOML/JSON into a generic enum and passing the wrong variant; renaming/refactors that swap config structs.

Related errors


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