{"record":{"id":"0ec77cd713f48720","repo":"HeyPuter/puter","slug":"unknown-error-0ec77c","errorCode":"unknown_error","errorMessage":"Failed to extract image URL from Gemini response","messagePattern":"Failed to extract image URL from Gemini response","errorType":"http","errorClass":"HttpError","httpStatus":400,"severity":"error","filePath":"src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts","lineNumber":262,"sourceCode":"                usageAmount: Math.max(inputTokenCount, 1),\n                costOverride: this.#toMicroCents(inputCostInCents),\n            },\n            {\n                usageType: `${usagePrefix}:output:text`,\n                usageAmount: Math.max(outputTextTokenCount, 1),\n                costOverride: this.#toMicroCents(outputTextCostInCents),\n            },\n            {\n                usageType: `${usagePrefix}:output:image`,\n                usageAmount: Math.max(outputImageTokenCount, 1),\n                costOverride: this.#toMicroCents(outputImageCostInCents),\n            },\n        ]);\n\n        const url = this.#extractImageUrl(response);\n\n        if (!url) {\n            throw new HttpError(\n                400,\n                'Failed to extract image URL from Gemini response',\n                { legacyCode: 'unknown_error' },\n            );\n        }\n\n        return url;\n    }\n\n    async #generateWithImagen(\n        prompt: string,\n        selectedModel: IGeminiImageModel,\n        params: IGenerateParams,\n    ): Promise<string> {\n        const actor = Context.get('actor');\n        if (!actor) {\n            throw new HttpError(401, 'actor not found in context', {\n                legacyCode: 'unauthorized',","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts#L244-L280","documentation":"Thrown by GeminiImageProvider.generate() (GeminiImageProvider.ts:262) after a successful generateContent API call when #extractImageUrl() returns undefined. That helper walks response.candidates[0].content.parts looking for a part with inlineData.data; if no such part exists (no image modality in the response), the provider cannot return an image. Note billing has already been recorded at this point. HTTP 400 with legacyCode unknown_error — the response shape was unexpected.","triggerScenarios":"Gemini returned a text-only response (image generation implicitly declined); content was filtered by Gemini's safety settings without an explicit error; the model returned candidates with no parts or parts without inlineData; an API version change altered the response envelope.","commonSituations":"Prompt tripped Gemini's safety filters (violence, NSFW, etc.) producing text refusal instead of an image; model quirk where it returns reasoning text but no image; transient provider behavior; SDK version mismatch changing response structure.","solutions":["Rephrase the prompt to avoid content likely to trip safety filters (violence, explicit, copyright, public figures).","Retry the request — transient non-image responses can occur; if it persists, the prompt/model is the issue.","Inspect the full Gemini response (candidates[0].content.parts, finishReason, safetyRatings) in logs to see why no image was returned.","If using a preview model, switch to a stable model id or check for API deprecation."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let lastErr;\nfor (let attempt = 0; attempt < 2; attempt++) {\n  try {\n    return await provider.generate(params);\n  } catch (e) {\n    lastErr = e;\n    if (e instanceof HttpError && e.status_code === 400 && e.message.includes('extract image URL')) {\n      continue; // retry once for transient non-image responses\n    }\n    throw e;\n  }\n}\nthrow lastErr;","preventionTips":["Avoid prompts likely to trip Gemini safety filters.","Log the full response when this occurs to diagnose whether it is filtering or an API change.","Prefer stable model ids over preview models to reduce response-shape drift."],"tags":["gemini","ai-image","upstream-response","content-filtering","unknown-error"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}