nautechsystems/nautilus_trader · error · anyhow::Error

Invalid config type for HyperliquidExecutionClientFactory. E

Error message

Invalid config type for HyperliquidExecutionClientFactory. Expected HyperliquidExecutionClientConfig, was {config:?}

What it means

HyperliquidExecutionClientFactory::create() downcasts the generic config to HyperliquidExecutionClientConfig and fails when the provided config is any other type. This mirrors the data factory check on the execution side.

Source

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

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

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

        // Hyperliquid uses netting for perpetual futures
        let oms_type = OmsType::Netting;

        // Hyperliquid is always margin (perpetual futures)
        let account_type = AccountType::Margin;

        let core = ExecutionClientCore::new(
            trader_id,
            ClientId::from(name),
            *HYPERLIQUID_VENUE,
            oms_type,
            hyperliquid_config.account_id,
            account_type,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the config passed to HyperliquidExecutionClientFactory is a HyperliquidExecutionClientConfig
  2. Check .exec_clients(...) wiring pairs the exec factory with an execution config
  3. Fix the config file so the execution client section deserializes into HyperliquidExecutionClientConfig
  4. Use the {config:?} in the message to identify the actual type passed

Example fix

// before
node_builder.add_exec_client_factory("HYPERLIQUID", HyperliquidExecutionClientFactory(), data_config);
// after
node_builder.add_exec_client_factory("HYPERLIQUID", HyperliquidExecutionClientFactory(), exec_config);
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

fn is_exec_config(config: &dyn ClientConfig) -> bool {
    config.as_any().downcast_ref::<HyperliquidExecutionClientConfig>().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 HyperliquidDataClientConfig (or any other config type) to the execution client factory — usually a miswired client registration in the TradingNode builder or wrong config section in the JSON/TOML config.

Common situations: Swapping data and execution config objects when wiring clients programmatically; config file sections deserialized into the wrong struct; reusing one config object for both factories.

Related errors


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