{"record":{"id":"9ed04fb5eba5a185","repo":"tinyhumansai/openhuman","slug":"exa-rejected-the-configured-api-key-http-status","errorCode":null,"errorMessage":"Exa rejected the configured API key (HTTP {status}). Check your Exa API key under Connections > Search engine.","messagePattern":"Exa rejected the configured API key \\(HTTP (.+?)\\)\\. Check your Exa API key under Connections > Search engine\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/search/tools/exa.rs","lineNumber":238,"sourceCode":"            .header(\"Accept\", \"application/json\")\n            .json(&body)\n            .send()\n            .await\n            .map_err(|e| {\n                tracing::warn!(\"[exa] request to {path} failed: {e}\");\n                anyhow::anyhow!(\"Exa request failed: {e}\")\n            })?;\n\n        let status = resp.status();\n        if !status.is_success() {\n            // Read and drop the body: Exa echoes the query back in errors and\n            // the message reaches the agent transcript.\n            let body_len = resp.text().await.unwrap_or_default().len();\n            tracing::warn!(status = %status, body_len, \"[exa] non-2xx response\");\n            if status == reqwest::StatusCode::UNAUTHORIZED\n                || status == reqwest::StatusCode::FORBIDDEN\n            {\n                anyhow::bail!(\n                    \"Exa rejected the configured API key (HTTP {status}). \\\n                     Check your Exa API key under Connections > Search engine.\"\n                );\n            }\n            anyhow::bail!(\"Exa returned non-2xx status {status}\");\n        }\n\n        resp.json().await.map_err(|e| {\n            tracing::warn!(\"[exa] failed to read response JSON: {e}\");\n            anyhow::anyhow!(\"Failed to read Exa response JSON: {e}\")\n        })\n    }\n\n    async fn post_documents(&self, path: &str, body: Value) -> anyhow::Result<Vec<ExaResultItem>> {\n        let value = self.post(path, body).await?;\n        let parsed: ExaSearchResponse = serde_json::from_value(value).map_err(|e| {\n            tracing::warn!(\"[exa] failed to parse {path} response: {e}\");\n            anyhow::anyhow!(\"Failed to parse Exa response: {e}\")","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/search/tools/exa.rs#L220-L256","documentation":"Exa answered 401/403 — the configured API key was rejected. The response body is deliberately read and dropped (Exa echoes the query back in errors), so the key is named without leaking body content.","triggerScenarios":"Thrown at src/openhuman/search/tools/exa.rs:238 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Update the Exa API key under Connections > Search engine","Verify the key is active and has quota on the Exa dashboard"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}