nautechsystems/nautilus_trader · error

Invalid config type for BetfairExecutionClientFactory. Expec

Error message

Invalid config type for BetfairExecutionClientFactory. Expected BetfairExecutionClientConfig, was {config:?}

What it means

BetfairExecutionClientFactory.create downcasts the incoming ClientConfig to BetfairExecutionClientConfig and errors when the config is any other type. It mirrors the data-client factory check but for execution clients.

Source

Thrown at crates/adapters/betfair/src/factories.rs:166

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

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

        betfair_config.validate()?;

        let credential = betfair_config.credential()?;
        let stream_config = betfair_config.stream_config();
        let currency = betfair_config.currency()?;

        let http_client = BetfairHttpClient::new(
            credential.clone(),
            None,
            None,
            None,
            betfair_config
                .proxy_url

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use BetfairExecutionClientConfig when creating the execution client.
  2. Ensure factories are registered with their matching config types so create() receives the right one.
  3. Validate the concrete config type before invoking create in dynamic wiring code.

Example fix

// before
config = BetfairDataClientConfig(...)
exec_client = BetfairExecutionClientFactory().create(..., config, ...)

// after
config = BetfairExecutionClientConfig(name=..., venue=..., api_key=..., username=..., password=...)
exec_client = BetfairExecutionClientFactory().create(..., config, ...)
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(config, BetfairExecutionClientConfig):
    raise TypeError(f"BetfairExecutionClientFactory requires BetfairExecutionClientConfig, got {type(config).__name__}")

Type guard

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

Try / catch

match factory.create(client_id, None, config, cache) {
    Ok(client) => client,
    Err(e) if e.to_string().contains("Invalid config type") => {
        panic!("wiring bug: wrong config for BetfairExecutionClientFactory: {e}")
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling BetfairExecutionClientFactory.create with a config that is not BetfairExecutionClientConfig (e.g. BetfairDataClientConfig or another venue's ExecutionClientConfig).

Common situations: Swapping data/execution configs when building a trading node; registering the wrong factory for a config class; tests intentionally passing a mismatched config (as in the factory tests).

Related errors


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