Mintplex-Labs/anything-llm · error · Error
${res.status} - ${res.statusText}. params: ${JSON.stringify(
Error message
${res.status} - ${res.statusText}. params: ${JSON.stringify({ auth: this.middleTruncate(process.env.AGENT_EXA_API_KEY, 5), q: query })} What it means
Thrown by the Exa (formerly Metaphor) search provider when a POST to the Exa API returns a non-OK status. Authentication uses AGENT_EXA_API_KEY as a Bearer token in the Authorization header. The request body specifies query, type, numResults, and contents. The error captures status, statusText, a truncated key, and the query.
Source
Thrown at server/utils/agents/aibitat/plugins/web-browsing.js:1069
const url = "https://api.exa.ai/search";
const { response, error } = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-api-key": process.env.AGENT_EXA_API_KEY,
},
body: JSON.stringify({
query: query,
type: "auto",
numResults: 10,
contents: {
text: true,
},
}),
})
.then((res) => {
if (res.ok) return res.json();
throw new Error(
`${res.status} - ${res.statusText}. params: ${JSON.stringify({ auth: this.middleTruncate(process.env.AGENT_EXA_API_KEY, 5), q: query })}`
);
})
.then((data) => {
return { response: data, error: null };
})
.catch((e) => {
this.super.handlerProps.log(`Exa Search Error: ${e.message}`);
return { response: null, error: e.message };
});
if (error)
return `There was an error searching for content. ${error}`;
const data = [];
response.results?.forEach((searchResult) => {
const { title, url, text, publishedDate } = searchResult;
data.push({View on GitHub (pinned to 526360e320)
Solutions
- Verify AGENT_EXA_API_KEY is set to a valid key from dashboard.exa.ai.
- A 401 means the Bearer token is wrong — check the truncated value in the error.
- A 429 means the plan rate limit is hit — upgrade or reduce search frequency.
- For 400 errors, verify the request body fields match Exa's current API spec (type, numResults, contents).
Example fix
// before
headers: { Authorization: `Bearer ${process.env.AGENT_EXA_API_KEY}`, ... },
body: JSON.stringify({ query, type: "auto", numResults: 10, contents: { text: true } }),
// throw on non-OK
// caller-side fix
if (!process.env.AGENT_EXA_API_KEY) {
return "AGENT_EXA_API_KEY is not configured.";
} Defensive patterns
Strategy: validation
Validate before calling
if (!process.env.AGENT_EXA_API_KEY) {
throw new Error("AGENT_EXA_API_KEY is not set. Configure it to use Exa search.");
} Try / catch
try {
const results = await exaSearch(query);
return results;
} catch (e) {
if (e.message.startsWith("401")) {
return "Exa API key invalid. Check AGENT_EXA_API_KEY.";
}
if (e.message.startsWith("429")) {
await new Promise(r => setTimeout(r, 3000));
return await exaSearch(query); // retry once
}
throw e;
} Prevention
- Verify AGENT_EXA_API_KEY is set before using Exa search.
- Monitor plan rate limits (requests per minute).
- Keep up with Exa API schema changes (renamed from Metaphor — field names may evolve).
- Validate the request body fields against the current Exa API spec.
When it happens
Trigger: Exa returns 401 (invalid or missing Bearer token), 429 (rate limit per plan), 400 (malformed request — wrong type value, unsupported contents config), or 5xx. An unset AGENT_EXA_API_KEY sends an empty Bearer token, always triggering 401.
Common situations: AGENT_EXA_API_KEY not configured; key from a free plan exhausted; API schema change (Exa renamed from Metaphor, endpoint/field names may have changed); concurrent requests exceeding the plan's requests-per-minute limit.
Related errors
- ${res.status} - ${res.statusText}. params: ${JSON.stringify(
- ${res.status} - ${res.statusText}. params: ${JSON.stringify(
- ${res.status} - ${res.statusText}. params: ${JSON.stringify(
- ${res.status} - ${res.statusText}. params: ${JSON.stringify(
- ${res.status} - ${res.statusText}. params: ${JSON.stringify(
AI-assisted analysis of Mintplex-Labs/anything-llm@526360e320 (2026-08-13).
Data as JSON: /api/errors/3fc0738d2ccdb968.
Report an issue: GitHub.