nautechsystems/nautilus_trader · critical · anyhow::Error
API credentials not configured
Error message
API credentials not configured
What it means
In the data-client factory, has_api_credentials() said a credential pair was available (key from config or AX_API_KEY, secret from config or AX_API_SECRET), but Credential::resolve then returned None - meaning a complete pair could not actually be assembled from the provided values plus environment. The classic cause is a half-configured pair: one component supplied in config or env and the other missing or empty, in a combination where the fallback rules cannot complete both sides.
Source
Thrown at crates/adapters/architect_ax/src/factories.rs:105
_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,
ax_config.max_retries,
ax_config.retry_delay_initial_ms,
ax_config.retry_delay_max_ms,
ax_config.proxy_url.clone(),
)
.map_err(|e| anyhow::anyhow!("Failed to create HTTP client: {e}"))?
} else {
AxHttpClient::new(
Some(ax_config.http_base_url()),
None, // orders_base_url
ax_config.http_timeout_secs,View on GitHub (pinned to a4b06ed870)
Solutions
- Provide BOTH api_key and api_secret in the AxDataClientConfig, or export BOTH AX_API_KEY and AX_API_SECRET
- Print env::var("AX_API_KEY").is_ok() and env::var("AX_API_SECRET").is_ok() right before node build to confirm the pair
- Watch for empty strings: an exported-but-empty var is not a usable credential
- Keep credentials in both places identical (config overrides env) to eliminate mixed sources
Example fix
# before
export AX_API_KEY=...
# AX_API_SECRET never set -> "API credentials not configured"
# after
export AX_API_KEY=...
export AX_API_SECRET=...
# or in config
let cfg = AxDataClientConfig::builder()
.api_key(Some(key))
.api_secret(Some(secret))
.build()?; Defensive patterns
Strategy: validation
Validate before calling
// Assert a complete pair exists before building the node
let (k, s) = (
std::env::var("AX_API_KEY").ok().or(config.api_key.clone()),
std::env::var("AX_API_SECRET").ok().or(config.api_secret.clone()),
);
ensure!(k.as_deref().map_or(false, |v| !v.is_empty()), "AX_API_KEY missing/empty");
ensure!(s.as_deref().map_or(false, |v| !v.is_empty()), "AX_API_SECRET missing/empty"); Prevention
- Set both vars in one place (a sourcing script or secret manager) so they cannot diverge
- Fail fast at process start with an explicit env check rather than deep inside factory creation
- In containers, use secrets files or injected env pairs, never partial manual exports
When it happens
Trigger: Setting api_key in config but neither api_secret in config nor AX_API_SECRET in the environment (or vice versa); exporting only one of AX_API_KEY/AX_API_SECRET; empty-string values that count as 'set' for one check but fail resolution; env vars removed between the two checks.
Common situations: Docker/systemd units where only one secret env var was added; CI pipelines masking one var; .env files with a typo'd variable name (AX_API_SECREY).
Related errors
- pandas is required for visualization; install it with `pip i
- {name} must not be None
- Chart name cannot be empty
- Chart function must be callable, was {type(f)}
- Invalid config type for AxDataClientFactory. Expected AxData
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/9f6a73b1474ddd03.
Report an issue: GitHub.