{"record":{"id":"83e626cf6353e5e6","repo":"continuedev/continue","slug":"data-error-message","errorCode":null,"errorMessage":"data.error.message","messagePattern":"data\\.error\\.message","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"core/llm/llms/Gemini.ts","lineNumber":400,"sourceCode":"      if (buffer.startsWith(\",\")) {\n        buffer = buffer.slice(1);\n      }\n\n      const parts = buffer.split(\"\\n,\");\n\n      let foundIncomplete = false;\n      for (let i = 0; i < parts.length; i++) {\n        const part = parts[i];\n        let data: GeminiChatResponse;\n        try {\n          data = JSON.parse(part) as GeminiChatResponse;\n        } catch (e) {\n          foundIncomplete = true;\n          continue; // yo!\n        }\n\n        if (\"error\" in data) {\n          throw new Error(data.error.message);\n        }\n\n        // In case of max tokens reached, gemini will sometimes return content with no parts, even though that doesn't match the API spec\n        const contentParts = data?.candidates?.[0]?.content?.parts;\n        if (contentParts) {\n          const textParts: MessagePart[] = [];\n          const toolCalls: ToolCallDelta[] = [];\n\n          for (const part of contentParts) {\n            if (\"text\" in part) {\n              textParts.push({ type: \"text\", text: part.text });\n            } else if (\"functionCall\" in part) {\n              const thoughtSignature = part.thoughtSignature;\n              toolCalls.push({\n                type: \"function\",\n                id: part.functionCall.id ?? uuidv4(),\n                function: {\n                  name: part.functionCall.name,","sourceCodeStart":382,"sourceCodeEnd":418,"githubUrl":"https://github.com/continuedev/continue/blob/5522c6f44ca0ac3528b37244818fbfa39b5af470/core/llm/llms/Gemini.ts#L382-L418","documentation":"Thrown by processGeminiResponse when the Gemini API response JSON contains an 'error' field; the error message from the payload is re-thrown directly. This surfaces Google's own error text (e.g. API key issues, safety blocks, quota, invalid model) during chat streaming.","triggerScenarios":"Streaming chat with an invalid GEMINI_API_KEY (API key not valid), quota exhaustion (429 RESOURCE_EXHAUSTED), requesting a nonexistent/deprecated model, or region-blocked API access, each returned as an error object in the response body.","commonSituations":"Expired/truncated GEMINI_API_KEY, free-tier keys hitting RPM/TPM limits during indexing loops, using gemini-pro after deprecation, or calling from an unsupported region/VPN.","solutions":["Match the message text: 'API key not valid' -> fix GEMINI_API_KEY; RESOURCE_EXHAUSTED -> backoff/quota; 'not found' -> fix model name","Test the key with a curl call to generativelanguage.googleapis.com","Add exponential backoff for RESOURCE_EXHAUSTED quota messages","Use the current model name (e.g. gemini-1.5-pro/gemini-2.0-flash) from Google's docs"],"exampleFix":"// before\nnew Gemini({ apiKey: process.env.GEMINI_API_KEY, model: 'gemini-pro' });\n// after\nnew Gemini({ apiKey: process.env.GEMINI_API_KEY?.trim(), model: 'gemini-2.0-flash' });","handlingStrategy":"try-catch","validationCode":"const key = process.env.GEMINI_API_KEY?.trim();\nif (!key) throw new Error('GEMINI_API_KEY required');","typeGuard":"function isGeminiApiError(e: unknown): boolean {\n  return e instanceof Error && /API key|quota|safety|RESOURCE_EXHAUSTED|PERMISSION|not found/i.test(e.message);\n}","tryCatchPattern":"try { for await (const m of geminiStream) { /* ... */ } }\ncatch (e) {\n  if (isGeminiApiError(e)) { handleConfigOrQuota(e); return; }\n  throw e;\n}","preventionTips":["Validate GEMINI_API_KEY at startup","Handle RESOURCE_EXHAUSTED with backoff","Retry safety-block responses with adjusted safetySettings"],"tags":["gemini","google-ai","api-error","streaming"],"backgroundTag":"llm-api-error","analyzedSha":"5522c6f44ca0ac3528b37244818fbfa39b5af470","analyzedAt":"2026-08-27T11:28:54.683Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}