{"record":{"id":"eea627358042d8fd","repo":"nautechsystems/nautilus_trader","slug":"failed-to-request-ax-whoami-e","errorCode":null,"errorMessage":"failed to request AX whoami: {e}","messagePattern":"failed to request AX whoami: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/client.rs","lineNumber":1379,"sourceCode":"    ///\n    /// AX reports fee rates per account rather than per user, and returns the accounts the\n    /// credentials can act on. The first entry is used, which is the account AX resolves when a\n    /// request carries no explicit selector. The rates are retained so later instrument requests,\n    /// including the periodic refresh, keep reporting them.\n    ///\n    /// Requires an authenticated client.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the request fails, the response carries no accounts, or the selected\n    /// account supplies no fee rates. An absent rate is not treated as zero, because a zero rate\n    /// is itself valid and a silent zero would outlive the response that caused it.\n    pub async fn request_account_fees(&self) -> anyhow::Result<(Decimal, Decimal)> {\n        let whoami = self\n            .inner\n            .get_whoami()\n            .await\n            .map_err(|e| anyhow::anyhow!(e))\n            .context(\"failed to request AX whoami\")?;\n\n        let Some(account) = whoami.accounts.first() else {\n            anyhow::bail!(\"AX whoami returned no accounts to resolve fees from\");\n        };\n\n        if whoami.accounts.len() > 1 {\n            log::warn!(\n                \"AX credentials cover {} accounts, using fee rates from {}\",\n                whoami.accounts.len(),\n                account.id,\n            );\n        }\n\n        let (Some(maker_fee), Some(taker_fee)) = (account.maker_fee, account.taker_fee) else {\n            anyhow::bail!(\"AX whoami account {} supplied no fee rates\", account.id);\n        };\n","sourceCodeStart":1361,"sourceCodeEnd":1397,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/http/client.rs#L1361-L1397","documentation":"`AxHttpClient::request_account_fees` first calls the AX `whoami` endpoint to discover the account from which fee tiers are resolved; if `get_whoami()` fails (HTTP error, auth rejection, network failure), the error is wrapped with context \"failed to request AX whoami\". This is the pre-flight account lookup for maker/taker fee resolution.","triggerScenarios":"Calling `request_account_fees` (during client connect/instrument load) when the whoami REST call fails: invalid or expired API key/secret, network/DNS failure, AX API returning 4xx/5xx, or base URL misconfiguration.","commonSituations":"Wrong or rotated API keys; keys lacking account-scoped permissions; AX API downtime; pointing the client at the wrong environment URL so the endpoint 404s.","solutions":["Inspect the chained source error for the HTTP status/transport cause.","Verify API key/secret are valid and have account read permissions.","Confirm `http_base_url` points at the correct AX environment.","Check network/proxy connectivity to the AX API (curl the whoami endpoint manually).","Retry if the cause was transient (5xx/timeout) — the client has retry settings that can be raised."],"exampleFix":"// diagnose\nmatch client.request_account_fees().await {\n    Ok((maker, taker)) => println!(\"fees: {maker} {taker}\"),\n    Err(e) => {\n        // anyhow chain shows \"failed to request AX whoami: <cause>\"\n        eprintln!(\"{e:#}\");\n        // fix keys/URL, then retry\n    }\n}","handlingStrategy":"retry","validationCode":"// before connect: sanity-check credentials and endpoint reachability\nlet key = std::env::var(\"AX_API_KEY\")?;\nlet secret = std::env::var(\"AX_API_SECRET\")?;\nassert!(!key.is_empty() && !secret.is_empty());\n// optionally ping the REST base URL before full connect\nlet status = reqwest::get(format!(\"{base}/health\")).await?.status();\nassert!(status.is_success(), \"AX API unreachable: {status}\");","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match client.request_account_fees().await {\n        Ok((m, t)) => break (m, t),\n        Err(e) if e.root_cause().to_string().contains(\"whoami\") && attempt < 2 => {\n            tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await;\n        }\n        Err(e) => return Err(e.context(\"whoami failed after retries; check AX_API_KEY/AX_API_SECRET\")),\n    }\n}","preventionTips":["Validate API key/secret and their permissions before starting the client.","Configure max_retries/retry_delay_max_ms for transient failures.","Monitor AX API status and alert on 4xx/5xx bursts.","Confirm the base URL matches the intended environment (prod vs test)."],"tags":["http","authentication","api","rust"],"backgroundTag":"api-request-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}