nautechsystems/nautilus_trader · error

Invalid config type for BetfairDataClientFactory. Expected B

Error message

Invalid config type for BetfairDataClientFactory. Expected BetfairDataConfig, was {config:?}

What it means

BetfairDataClientFactory::create tried to downcast the passed &dyn ClientConfig to BetfairDataConfig and failed — the config object is a different concrete type. This is a bootstrap/wiring error: the TradingNode or custom client setup is constructing the Betfair data client with a config that is not the Betfair-specific one, so creation aborts before any connection is made.

Source

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

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

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

        betfair_config.validate()?;

        let credential = betfair_config.credential()?;
        let stream_config = betfair_config.stream_config();
        let nav_filter = betfair_config.navigation_filter();
        let currency = betfair_config.currency()?;
        let min_notional = betfair_config.min_notional()?;

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

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Ensure the config-map entry routed to BetfairDataClientFactory is a BetfairDataConfig instance.
  2. When building clients manually, downcast-check the config before calling create and construct the matching type.
  3. Review the factory-to-config pairing in the TradingNode/routing configuration.

Example fix

// before: map pairs data factory with exec config
config_map.insert("BETFAIR".to_string(), Box::new(BetfairExecConfig::default()));

// after
config_map.insert("BETFAIR".to_string(), Box::new(BetfairDataConfig::default()));
Defensive patterns

Strategy: type-guard

Validate before calling

let is_valid = config
    .as_any()
    .downcast_ref::<BetfairDataConfig>()
    .is_some();
if !is_valid {
    return Err(anyhow::anyhow!("expected BetfairDataConfig for data factory"));
}

Type guard

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

Prevention

When it happens

Trigger: Registering BetfairDataClientFactory in a config map whose entry provides a different config type (e.g. BetfairExecConfig or another venue's config); custom bootstraps that build factories generically and pass the wrong config instance.

Common situations: Copy-paste errors in a broker/venue config map pairing the data factory with the wrong config struct; manual client construction mixing data and exec config types.

Related errors


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