{"record":{"id":"9f6a73b1474ddd03","repo":"nautechsystems/nautilus_trader","slug":"api-credentials-not-configured","errorCode":null,"errorMessage":"API credentials not configured","messagePattern":"API credentials not configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/factories.rs","lineNumber":107,"sourceCode":"    ) -> anyhow::Result<Box<dyn DataClient>> {\n        let ax_config = config\n            .as_any()\n            .downcast_ref::<AxDataClientConfig>()\n            .ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"Invalid config type for AxDataClientFactory. Expected AxDataClientConfig, was {config:?}\",\n                )\n            })?\n            .clone();\n\n        let client_id = ClientId::from(name);\n\n        let http_client = if ax_config.has_api_credentials() {\n            let credential = Credential::resolve(\n                ax_config.api_key.clone().map(|value| value.into_inner()),\n                ax_config.api_secret.clone().map(|value| value.into_inner()),\n            )\n            .ok_or_else(|| anyhow::anyhow!(\"API credentials not configured\"))?;\n\n            AxHttpClient::with_credentials(\n                credential.api_key().to_string(),\n                credential.api_secret().to_string(),\n                Some(ax_config.http_base_url()),\n                None, // orders_base_url\n                ax_config.http_timeout_secs,\n                ax_config.max_retries,\n                ax_config.retry_delay_initial_ms,\n                ax_config.retry_delay_max_ms,\n                ax_config\n                    .proxy_url\n                    .as_ref()\n                    .map(|url| url.expose_secret().to_owned()),\n            )\n            .map_err(|e| anyhow::anyhow!(\"Failed to create HTTP client: {e}\"))?\n        } else {\n            AxHttpClient::new(","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/factories.rs#L89-L125","documentation":"When the AX data config DOES have API credentials configured (`has_api_credentials()` is true), the factory tries to resolve them into a `Credential` via `Credential::resolve`. If resolution returns None — the provided key/secret are empty or cannot be combined into a usable credential — the factory raises \"API credentials not configured\". It protects against silently building an authenticated client with blank credentials.","triggerScenarios":"Calling `AxDataClientFactory.create` with a config where `api_key`/`api_secret` are set to empty strings, or where only one of key/secret is present and `Credential::resolve` cannot form a pair.","commonSituations":"Environment variables or config file containing empty-string API key/secret; a placeholder value stripped to empty by secret redaction; partial credential setup where only `api_key` was filled in.","solutions":["Set both AX_API_KEY and AX_API_SECRET (or the config's `api_key`/`api_secret` fields) to non-empty values.","If you intended an unauthenticated client, remove the credential fields entirely instead of passing empty strings so `has_api_credentials()` returns false.","Log/inspect the config (without secrets) to confirm both fields are populated before calling create.","Check for secret-management layers (env templating, vault injection) that may substitute empty values at deploy time."],"exampleFix":"// before\nlet config = AxDataClientConfig { api_key: Some(\"\".into()), api_secret: Some(secret.into()), .. };\n\n// after\nlet config = AxDataClientConfig {\n    api_key: Some(api_key), // non-empty, e.g. from env\n    api_secret: Some(secret),\n    ..\n};","handlingStrategy":"validation","validationCode":"// before create\nlet key = ax_config.api_key.as_ref().map(|k| k.into_inner()).unwrap_or_default();\nlet secret = ax_config.api_secret.as_ref().map(|s| s.into_inner()).unwrap_or_default();\nif !key.is_empty() || !secret.is_empty() {\n    assert!(!key.is_empty() && !secret.is_empty(), \"AX credentials must be both set or both unset\");\n}","typeGuard":null,"tryCatchPattern":"match factory.create(name, config, ...) {\n    Err(e) if e.to_string() == \"API credentials not configured\" => {\n        eprintln!(\"check AX_API_KEY / AX_API_SECRET: set both, or neither for unauthenticated use\");\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Validate at startup that both key and secret are non-empty when auth is required.","Never set credential fields to empty strings; omit them for unauthenticated use.","Verify secret-injection (env templating/vault) actually populated the values.","Rotate keys without leaving blanks in the config file."],"tags":["credentials","authentication","configuration","rust"],"backgroundTag":"missing-credentials","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}