danny-avila/LibreChat · error · Error

Request failed with status ${response.status}: ${json.error.

Error message

Request failed with status ${response.status}: ${json.error.message}

What it means

Thrown by GoogleSearch._call() when the fetch to the Custom Search JSON API returns a non-2xx status. It surfaces `response.status` and `json.error.message` from Google's error body. Common upstream causes: invalid/expired API key, disabled Custom Search API, exhausted daily quota (100/day free), invalid/missing cx (CSE ID), or a malformed query. Note: if Google returns a non-OK body without an `error.message` field, this line will instead throw a TypeError reading `json.error.message` — a latent fragility.

Source

Thrown at api/app/clients/tools/structured/GoogleSearch.js:72

  async _call(input) {
    const { query, max_results = 5 } = input;

    const response = await fetch(
      `https://www.googleapis.com/customsearch/v1?key=${this.apiKey}&cx=${
        this.searchEngineId
      }&q=${encodeURIComponent(query)}&num=${max_results}`,
      {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },
      },
    );

    const json = await response.json();
    if (!response.ok) {
      throw new Error(`Request failed with status ${response.status}: ${json.error.message}`);
    }

    return JSON.stringify(json);
  }
}

module.exports = GoogleSearchResults;

View on GitHub (pinned to 5ff282f900)

Solutions

  1. Read the surfaced status and json.error.message — 403 → rotate/fix the API key and enable the API; 429 → raise quota or wait; 400 → verify GOOGLE_CSE_ID.
  2. Verify billing/quota in Google Cloud Console > APIs & Services > Custom Search API.
  3. Confirm the API key has the Custom Search API enabled and is not restricted in a way that blocks it.
  4. Wrap _call() in try/catch and degrade gracefully (return a 'search unavailable' message to the agent).
  5. If you hit the TypeError variant, patch the line to guard `json?.error?.message`.

Example fix

// before — upstream 429 surfaces raw
const out = await searchTool.invoke('latest news');

// caller-side guard
try {
  const out = await searchTool.invoke('latest news');
} catch (e) {
  if (/status 429/.test(e.message)) return 'Search quota exceeded, try later.';
  throw e;
}

// library hardening (optional)
//   throw new Error(`Request failed ${response.status}: ${json?.error?.message ?? response.statusText}`);
Defensive patterns

Strategy: try-catch

Validate before calling

function isLikelyValidGoogleSearchCall(args) {
  return Boolean(args?.query) && Boolean(process.env.GOOGLE_SEARCH_API_KEY) && Boolean(process.env.GOOGLE_CSE_ID);
}

Type guard

function isQuotaError(e) {
  return /status 429/.test(e?.message || '');
}

Try / catch

try {
  const out = await searchTool.invoke(query);
} catch (e) {
  const msg = e.message || '';
  if (/status 403/.test(msg)) return 'Google Search API key invalid or API disabled.';
  if (/status 429/.test(msg)) return 'Search quota exceeded for today.';
  if (/status 400/.test(msg)) return 'Invalid Custom Search Engine ID.';
  throw e;
}

Prevention

When it happens

Trigger: Any `_call()` invocation against https://www.googleapis.com/customsearch/v1?key=...&cx=...&q=... where the response status is not ok — e.g., 403 (API key invalid / API disabled), 429 (quota exceeded), 400 (bad cx), or 503.

Common situations: Quota hit after the free 100 queries/day; API key was rotated in the console but not in .env; the Custom Search Engine was deleted or its ID changed; the project lacks the Custom Search API enabled; transient Google 5xx during heavy load; non-ASCII query that wasn't encoded (note the call already encodeURIComponent's q).

Related errors


AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12). Data as JSON: /api/errors/4a4c600a0027e852. Report an issue: GitHub.