{"record":{"id":"6b38525442c1bd59","repo":"thedotmack/claude-mem","slug":"gemini-api-error-status-response-status","errorCode":null,"errorMessage":"Gemini API error (status ${response.status})","messagePattern":"Gemini API error \\(status (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/services/worker/GeminiProvider.ts","lineNumber":365,"sourceCode":"        response = await this.fetchGenerateContent(url, contents, priorRequestId, attemptSignal);\n      } catch (networkError: unknown) {\n        // Network failures, aborts, DNS, etc.\n        const err = networkError instanceof Error ? networkError : new Error(String(networkError));\n        throw classifyGeminiError({\n          cause: err,\n        });\n      }\n\n      const requestId = response.headers.get('x-goog-request-id') ?? response.headers.get('x-request-id');\n      if (requestId) {\n        priorRequestId = requestId;\n      } else {\n        logger.debug('SDK', 'Gemini response missing request-id header; retry dedup is best-effort');\n      }\n\n      if (!response.ok) {\n        const errorBody = await response.text();\n        throw classifyGeminiError({\n          status: response.status,\n          bodyText: errorBody,\n          headers: response.headers,\n          cause: new Error(`Gemini API error (status ${response.status})`),\n          ...(requestId ? { requestId } : {}),\n        });\n      }\n\n      return await response.json() as GeminiResponse;\n    }, { label: `Gemini ${model}`, abortSignal: signal, ...(signal ? { maxRetries: 0 } : {}) });\n\n    if (!data.candidates?.[0]?.content?.parts?.[0]?.text) {\n      logger.error('SDK', 'Empty response from Gemini');\n      return { content: '' };\n    }\n\n    const content = data.candidates[0].content.parts[0].text;\n    const tokensUsed = data.usageMetadata?.totalTokenCount;","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/services/worker/GeminiProvider.ts#L347-L383","documentation":"When the Gemini generateContent endpoint returns a non-2xx status, the provider reads the response body and throws classifyGeminiError with status, bodyText, headers, and requestId attached. The classifier produces a structured error (e.g. rate limit, auth, invalid request) so callers can react per status instead of parsing raw HTTP responses themselves.","triggerScenarios":"A fetch succeeds at the transport level but the API responds with 4xx/5xx: 429 rate limit/quota, 401/403 bad or missing API key, 400 malformed request or unsupported model, 5xx server-side failure.","commonSituations":"Expired or revoked GEMINI_API key; model name typo or deprecated model; quota exhausted after heavy multi-turn usage; Gemini incident causing 500/503 responses.","solutions":["Read the classified error's status/body to identify the cause (401/403 → fix API key; 429 → back off; 400 → fix request/model)","Retry only retryable classifications (429 with retry-after, 5xx) using backoff","Verify the model name and request payload against the current Gemini API schema","Check Google's status page for outages when seeing persistent 5xx"],"exampleFix":"// before\nconst text = await provider.query(messages); // throws on 429\n// after\ntry {\n  const text = await provider.query(messages);\n} catch (e) {\n  if ((e as GeminiError).status === 429) await waitMs(e.retryAfterMs ?? 60000);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Validate key and model before calling\nif (!process.env.GEMINI_API_KEY) throw new Error('GEMINI_API_KEY missing');\nconst SUPPORTED_MODELS = ['gemini-2.0-flash', 'gemini-1.5-pro'];\nif (!SUPPORTED_MODELS.includes(model)) throw new Error(`unsupported model: ${model}`);","typeGuard":"const isGeminiHttpError = (e: unknown): e is { status: number; bodyText?: string; classification: string; retryAfterMs?: number } =>\n  typeof e === 'object' && e !== null && typeof (e as any).status === 'number';","tryCatchPattern":"try {\n  const text = await provider.query(messages);\n} catch (e) {\n  if (isGeminiHttpError(e)) {\n    if (e.status === 429) { await delay(e.retryAfterMs ?? 60000); return retry(); }\n    if (e.status >= 500) { return backoffRetry(); }\n    if (e.status === 401 || e.status === 403) { throw new Error('Check GEMINI_API_KEY'); }\n  }\n  throw e;\n}","preventionTips":["Branch on the classified status rather than string-matching message text","Retry only 429 (with retry-after) and 5xx; fail fast on 4xx","Verify model names against the current Gemini API when a 400 appears","Monitor GEMINI_API_KEY validity and quota usage","Check Google's status page during suspected 5xx incidents"],"tags":["gemini","http","api"],"backgroundTag":"http-error-response","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}