{"record":{"id":"cbe03b9f84ef34f1","repo":"musistudio/claude-code-router","slug":"gateway-tavily-web-search-api-key-is-not-configu","errorCode":null,"errorMessage":"[gateway] Tavily web search API key is not configured.","messagePattern":"\\[gateway\\] Tavily web search API key is not configured\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/core/src/gateway/features/hosted-web-search/discovery.ts","lineNumber":628,"sourceCode":"  const apiKey = searchEnv(input, \"SERPAPI_API_KEY\");\n  if (!apiKey) {\n    console.warn(\"[gateway] SerpAPI web search API key is not configured.\");\n    return [];\n  }\n  const url = new URL(searchEnv(input, \"SERPAPI_SEARCH_ENDPOINT\") || \"https://serpapi.com/search.json\");\n  url.searchParams.set(\"api_key\", apiKey);\n  url.searchParams.set(\"engine\", \"google\");\n  url.searchParams.set(\"q\", input.query);\n  url.searchParams.set(\"num\", String(input.count));\n  const raw = await fetchJson(url.toString(), { signal: AbortSignal.timeout(input.timeoutMs) });\n  const items = isRecord(raw) && Array.isArray(raw.organic_results) ? raw.organic_results : [];\n  return items.map((item) => webSearchResult(item, \"title\", \"link\", \"snippet\")).filter(isWebSearchProviderResult);\n}\n\nasync function searchTavily(input: WebSearchProviderInput): Promise<WebSearchProviderResult[]> {\n  const apiKey = searchEnv(input, \"TAVILY_API_KEY\");\n  if (!apiKey) {\n    console.warn(\"[gateway] Tavily web search API key is not configured.\");\n    return [];\n  }\n  const raw = await fetchJson(searchEnv(input, \"TAVILY_SEARCH_ENDPOINT\") || \"https://api.tavily.com/search\", {\n    body: JSON.stringify({\n      api_key: apiKey,\n      max_results: input.count,\n      query: input.query,\n      search_depth: \"basic\"\n    }),\n    headers: { \"content-type\": \"application/json\" },\n    method: \"POST\",\n    signal: AbortSignal.timeout(input.timeoutMs)\n  });\n  const items = isRecord(raw) && Array.isArray(raw.results) ? raw.results : [];\n  return items.map((item) => webSearchResult(item, \"title\", \"url\", \"content\")).filter(isWebSearchProviderResult);\n}\n\nasync function searchExa(input: WebSearchProviderInput): Promise<WebSearchProviderResult[]> {","sourceCodeStart":610,"sourceCodeEnd":646,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/gateway/features/hosted-web-search/discovery.ts#L610-L646","documentation":"The Tavily web search provider was selected, but TAVILY_API_KEY is not present in the resolved environment. The provider returns an empty result list, degrading search-augmented responses silently.","triggerScenarios":"Setting web search provider to \"tavily\" without TAVILY_API_KEY; the key living only in a dev shell while the gateway runs as a daemon.","commonSituations":"Key from tavily.com not exported; .env file not copied into the deployment; env var naming mismatch.","solutions":["Set TAVILY_API_KEY in the gateway environment","Confirm the gateway process can read it (logs or /proc/<pid>/environ)","Restart the gateway"],"exampleFix":"# before\nWEB_SEARCH_PROVIDER=tavily\n\n# after\nTAVILY_API_KEY=tvly-...\nWEB_SEARCH_PROVIDER=tavily","handlingStrategy":"validation","validationCode":"if (!process.env.TAVILY_API_KEY) throw new Error(\"TAVILY_API_KEY required for tavily provider\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate keys at startup","Use persistent .env loading in the gateway process","Monitor empty search results as a key-missing signal"],"tags":["web-search","tavily","env-var","api-key"],"backgroundTag":"missing-env-var","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}