Mintplex-Labs/anything-llm · error
- . params: )}
Error message
${res.status} - ${res.statusText}. params: ${JSON.stringify({ auth: this.middleTruncate(process.env.AGENT_SERPER_DEV_KEY, 5), q: query })} What it means
Thrown inside the Serper.dev branch of the web-browsing plugin when the POST to google.serper.dev/search returns non-ok. The request sends X-API-KEY: AGENT_SERPER_DEV_KEY with a JSON body {q: query}; the error embeds status, statusText, query, and the key middle-truncated to 5 chars. The wrapping .catch logs 'Serper.dev Error' and returns the message to the agent as an error string rather than rethrowing.
Solutions
- Confirm AGENT_SERPER_DEV_KEY is a valid serper.dev key and restart the server after .env changes.
- Check remaining credits/rate limits on the Serper dashboard for 429s; upgrade or wait out the window.
- For persistent 4xx, curl the endpoint directly with the X-API-KEY header to see Serper's own error body.
Example fix
# before curl-equivalent fails: 403 - Forbidden (key from another provider) AGENT_SERPER_DEV_KEY=serpapi-key-oops # after AGENT_SERPER_DEV_KEY=<real serper.dev key> # restart server
Defensive patterns
Strategy: validation
Validate before calling
const KEY = process.env.AGENT_SERPER_DEV_KEY;
if (!KEY || KEY.length < 20) {
throw new Error("AGENT_SERPER_DEV_KEY missing or malformed — set a valid serper.dev key and restart");
} Try / catch
const out = await webSearch(query);
if (typeof out === "string" && out.includes("Serper.dev Error")) {
if (/40[13]/.test(out)) fixSerperKey();
else if (out.includes("429")) backoffThenRetry(query); // credits/QPS
else checkRequestBody(out);
} Prevention
- Fund the serper.dev plan and monitor remaining credits (free tier is 2500 searches).
- Keep provider env vars mutually exclusive to avoid cross-key mistakes.
- Restart the server after updating keys.
When it happens
Trigger: AGENT_SERPER_DEV_KEY missing/invalid (401/403); free-tier 2500-credit quota exhausted or rate limited (429); malformed query payload (400); serper.dev outage (5xx).
Common situations: Key created but never funded after trial; server process predates the .env change adding the key; using a SerpApi key in AGENT_SERPER_DEV_KEY.
Related errors
- - . params: )}
- - . params: )}
- - . params: )}
- Access denied - path outside allowed directories.
- Community Hub connection key not found
AI-assisted analysis of Mintplex-Labs/anything-llm@a145d4d87d (2026-08-18).
Data as JSON: /api/errors/c36b5bf3af6a85d8.
Report an issue: GitHub.
Appendix: source
Thrown at server/utils/agents/aibitat/plugins/web-browsing.js:533
`${this.caller}: Using Serper.dev to search for "${
query.length > 100 ? `${query.slice(0, 100)}...` : query
}"`
);
const { response, error } = await fetch(
"https://google.serper.dev/search",
{
method: "POST",
headers: {
"X-API-KEY": process.env.AGENT_SERPER_DEV_KEY,
"Content-Type": "application/json",
},
body: JSON.stringify({ q: query }),
redirect: "follow",
}
)
.then((res) => {
if (res.ok) return res.json();
throw new Error(
`${res.status} - ${res.statusText}. params: ${JSON.stringify({ auth: this.middleTruncate(process.env.AGENT_SERPER_DEV_KEY, 5), q: query })}`
);
})
.then((data) => {
return { response: data, error: null };
})
.catch((e) => {
this.super.handlerProps.log(`Serper.dev Error: ${e.message}`);
return { response: null, error: e.message };
});
if (error)
return `There was an error searching for content. ${error}`;
const data = [];
if (response.hasOwnProperty("knowledgeGraph"))
data.push(response.knowledgeGraph);
response.organic?.forEach((searchResult) => {
const { title, link, snippet } = searchResult;View on GitHub (pinned to a145d4d87d)