{"record":{"id":"a65cc0d920822d08","repo":"chatboxai/chatbox","slug":"web-search-failed-with-status-response-status","errorCode":null,"errorMessage":"Web search failed with status ${response.status}","messagePattern":"Web search failed with status (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/shared/services/native-web-search.ts","lineNumber":263,"sourceCode":"    search_depth: 'basic',\n    include_domains: [],\n    exclude_domains: [],\n  }\n  if (maxResults !== undefined) {\n    body.max_results = maxResults\n  }\n\n  const response = await fetchFn(`${host}/search`, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application/json',\n      Authorization: `Bearer ${options.apiKey ?? ''}`,\n    },\n    body: JSON.stringify(body),\n    signal: options.signal,\n  })\n  if (!response.ok) {\n    throw new Error(`Web search failed with status ${response.status}`)\n  }\n\n  const payload = (await response.json()) as { results?: TavilyResponseItem[] }\n  const results = Array.isArray(payload.results) ? payload.results : []\n  // No link filtering: matches the old renderer Tavily provider, which returned every\n  // result Tavily sent (link-less items included) for the model to use.\n  const items = results.map((item) => ({\n    title: item.title ?? '',\n    link: item.url ?? '',\n    snippet: item.content ?? '',\n  }))\n  return maxResults !== undefined ? items.slice(0, maxResults) : items\n}\n\n/**\n * Chatbox build-in search — single implementation behind the renderer's `build-in`\n * provider (which injects an afetch `fetchFn` for retry + Chatbox error parsing, plus the\n * Chatbox platform `headers`) and the native shell. `POST /api/tool/web-search`, license","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/chatboxai/chatbox/blob/81571269addb6bafb589a920b2883f1e1e084fd1/src/shared/services/native-web-search.ts#L245-L281","documentation":"Thrown by searchNativeTavily (src/shared/services/native-web-search.ts:263) when POST ${apiHost||https://api.tavily.com}/search returns a non-2xx status. The body is { query, search_depth:'basic', include_domains:[], exclude_domains:[], max_results? } with Authorization: Bearer <apiKey>. The throw happens before body parsing, so only the raw HTTP status is reported. Unlike Querit, Tavily has no separate business error_code path, so any non-ok response is a hard failure.","triggerScenarios":"Tavily POST returns response.ok === false: 401 for missing/invalid apiKey (an empty key sends `Bearer `), 429 for quota/rate limit (Tavily free tier is small), 5xx outage, or a wrong apiHost override returning a non-2xx. Aborting options.signal mid-flight can also surface here.","commonSituations":"User picked Tavily without entering a key; free-tier quota exhausted after a few searches; options.apiHost customized to a wrong/mocked host that does not implement /search; Tavily regional block; key pasted with stray whitespace/newline.","solutions":["Confirm options.apiKey is set, trimmed, and matches a valid Tavily key with remaining quota.","Leave options.apiHost empty to use the default https://api.tavily.com, or ensure a custom host implements POST /search with Tavily's contract.","Catch the error and fall back to another provider or return no results so the chat continues.","On 429, surface 'quota exceeded' to the user rather than silently retrying.","Strip whitespace/newlines from the key before storing it in settings."],"exampleFix":"// before\nconst host = settings.apiHost\nconst items = await searchNativeTavily(query, { apiKey: settings.apiKey, apiHost: host })\n\n// after\nconst apiKey = settings.apiKey.trim()\nif (!apiKey) return []\ntry {\n  return await searchNativeTavily(query, { apiKey, apiHost: settings.apiHost })\n} catch (e) {\n  console.warn('tavily search failed', e)\n  return []\n}","handlingStrategy":"validation","validationCode":"// Block the call before it reaches Tavily when there is no usable key\nconst apiKey = (settings.apiKey ?? '').trim()\nif (settings.provider === 'tavily' && !apiKey) return []","typeGuard":null,"tryCatchPattern":"// Fall back to another provider on failure\ntry {\n  return await searchNativeTavily(query, { apiKey, apiHost, signal })\n} catch (e) {\n  console.warn('tavily failed', e)\n  return []\n}","preventionTips":["Trim the Tavily key on save to avoid whitespace/newline auth failures.","Leave apiHost empty unless you are targeting a known Tavily-compatible endpoint.","Watch free-tier usage; 429 means quota, not a bug.","Prefer maxResults to bound both request size and response cost."],"tags":["web-search","network","api","tavily","auth"],"backgroundTag":null,"analyzedSha":"81571269addb6bafb589a920b2883f1e1e084fd1","analyzedAt":"2026-08-12T21:51:44.981Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}