nautechsystems/nautilus_trader · error · anyhow::Error

Invalid config type for HyperliquidDataClientFactory. Expect

Error message

Invalid config type for HyperliquidDataClientFactory. Expected HyperliquidDataClientConfig, was {config:?}

What it means

HyperliquidDataClientFactory::create() downcasts the generic config to HyperliquidDataClientConfig and fails when the provided config is any other type. Factories are type-erased, so a config wired to the wrong factory produces this error.

Source

Thrown at crates/adapters/hyperliquid/src/factories.rs:89

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

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

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

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

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

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the config registered for the Hyperliquid data client is a HyperliquidDataClientConfig
  2. Check the node builder wiring: .data_clients(...) must pair HyperliquidDataClientConfig with the data factory
  3. Fix JSON/TOML config so the data client section deserializes into HyperliquidDataClientConfig
  4. Log {config:?} (already in the message) to see which type was actually passed

Example fix

// before
node_builder.add_data_client_factory("HYPERLIQUID", HyperliquidDataClientFactory(), exec_config);
// after
node_builder.add_data_client_factory("HYPERLIQUID", HyperliquidDataClientFactory(), data_config);
Defensive patterns

Strategy: type-guard

Validate before calling

if config.as_any().downcast_ref::<HyperliquidDataClientConfig>().is_none() {
    panic!("data client config must be HyperliquidDataClientConfig");
}

Type guard

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

Try / catch

match factory.create(name, config, cache, clock) { Err(e) if e.to_string().contains("Invalid config type") => fix_client_wiring(), other => other }

Prevention

When it happens

Trigger: Passing a HyperliquidExecutionClientConfig (or any other client config) to the data client factory — typically via a misconfigured client registration in the node config, e.g. mapping the wrong config type to the HYPERLIQUID data client name.

Common situations: Copy-paste mistakes in TradingNode config where execution and data client configs are swapped; JSON/TOML config deserializing into the wrong config struct; programmatic wiring putting the wrong config object into the factory map.

Related errors


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