nautechsystems/nautilus_trader · error · anyhow::Error
Invalid config type for AxDataClientFactory. Expected AxData
Error message
Invalid config type for AxDataClientFactory. Expected AxDataClientConfig, was {config:?} What it means
AxDataClientFactory::create downcasts the passed &dyn ClientConfig to AxDataClientConfig; failure means the caller handed the wrong config object type. The message prints what was actually received. This only happens when wiring factories manually or through a custom FactoryRouter - the standard Nautilus TraderNode path always pairs the right config with the right factory.
Source
Thrown at crates/adapters/architect_ax/src/factories.rs:94
impl Default for AxDataClientFactory {
fn default() -> Self {
Self::new()
}
}
impl DataClientFactory for AxDataClientFactory {
fn create(
&self,
name: &str,
config: &dyn ClientConfig,
_cache: CacheView,
_clock: Rc<RefCell<dyn Clock>>,
) -> anyhow::Result<Box<dyn DataClient>> {
let ax_config = config
.as_any()
.downcast_ref::<AxDataClientConfig>()
.ok_or_else(|| {
anyhow::anyhow!(
"Invalid config type for AxDataClientFactory. Expected AxDataClientConfig, was {config:?}",
)
})?
.clone();
let client_id = ClientId::from(name);
let http_client = if ax_config.has_api_credentials() {
let credential =
Credential::resolve(ax_config.api_key.clone(), ax_config.api_secret.clone())
.ok_or_else(|| anyhow::anyhow!("API credentials not configured"))?;
AxHttpClient::with_credentials(
credential.api_key().to_string(),
credential.api_secret().to_string(),
Some(ax_config.http_base_url()),
None, // orders_base_url
ax_config.http_timeout_secs,View on GitHub (pinned to a4b06ed870)
Solutions
- Pass an AxDataClientConfig (or its Python twin) to AxDataClientFactory::create
- Use TradingNode with the AX routing config instead of manual factory calls, which enforces the pairing
- Check the {config:?} payload in the message to see which config actually arrived
Example fix
// before
let data_client = AxDataClientFactory.create(
"AX",
&exec_config, // AxExecClientConfig -> downcast fails
cache_view,
clock,
)?;
// after
let data_client = AxDataClientFactory.create(
"AX",
&AxDataClientConfig::default(),
cache_view,
clock,
)?; Defensive patterns
Strategy: type-guard
Type guard
// Rust
fn is_ax_data_config(cfg: &dyn ClientConfig) -> bool {
cfg.as_any().downcast_ref::<AxDataClientConfig>().is_some()
}
# Python
isinstance(config, AxDataClientConfig) Try / catch
match AxDataClientFactory.create(name, config, view, clock) {
Err(e) if e.to_string().contains("Invalid config type") => {
panic_with_expected_type(e, "AxDataClientConfig");
}
r => r?,
} Prevention
- Prefer TradingNode routing over manual factory.create() calls
- Keep data and exec config construction adjacent in code with distinct variable names
- Add a unit test asserting your wiring passes each factory its matching config type
When it happens
Trigger: Calling AxDataClientFactory.create() with an AxExecClientConfig, a config from another adapter, or a custom ClientConfig implementation; reusing one config object for both the data and execution factories in hand-rolled Rust wiring.
Common situations: Custom tooling that registers factories generically over Vec<Box<dyn ClientConfig>>; copy-paste wiring code where the data and exec configs were swapped.
Related errors
- Invalid config type for AxExecutionClientFactory. Expected A
- API credentials not configured
- Failed to create HTTP client: {e}
- height must be positive, was {self.height}
- pandas is required for report generation; install it with `p
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/0dcb33f1ec6505d2.
Report an issue: GitHub.