{"record":{"id":"d3f80bced388a04b","repo":"tinyhumansai/openhuman","slug":"failed-to-parse-exa-response-e","errorCode":null,"errorMessage":"Failed to parse Exa response: {e}","messagePattern":"Failed to parse Exa response: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/search/tools/exa.rs","lineNumber":256,"sourceCode":"                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}\")\n        })?;\n        tracing::debug!(path, result_count = parsed.results.len(), \"[exa] call ok\");\n        Ok(parsed.results)\n    }\n\n    fn render_plain(&self, results: &[ExaResultItem], heading: &str, limit: usize) -> String {\n        if results.is_empty() {\n            return format!(\"No Exa results for: {heading}\");\n        }\n\n        let mut lines = vec![format!(\"Search results for: {heading} (via Exa)\")];\n        for (i, item) in results.iter().take(limit).enumerate() {\n            lines.push(format!(\"{}. {}\", i + 1, item.display_title()));\n            lines.push(format!(\"   {}\", item.url.trim()));\n            if let Some(date) = non_empty(item.published_date.as_deref()) {\n                lines.push(format!(\"   Published: {date}\"));\n            }\n            if let Some(author) = non_empty(item.author.as_deref()) {","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/search/tools/exa.rs#L238-L274","documentation":"Thrown in post_documents after post() has already delivered parsed JSON: converting the 'results' array of documents/contents endpoints into Vec<ExaResultItem> fails because individual items lack expected fields (id/title/url/text) or carry unexpected types. The transport succeeded; the faulty input is the shape of ExaResultItem entries in the response payload.","triggerScenarios":"Thrown at src/openhuman/search/tools/exa.rs:256 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Inspect the logged parse error and relax ExaResultItem fields to Option<> where Exa legitimately omits them.","Add #[serde(default)] / alias attributes to tolerate field renames or additions.","Log and skip individual unparseable items instead of failing the whole batch.","Pin a response fixture test to catch Exa schema drift early."],"exampleFix":null,"handlingStrategy":"fallback","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-14T00:17:10.932Z"}