{"record":{"id":"ca516730c5c1e0e1","repo":"HeyPuter/puter","slug":"insufficient-funds-ca5167","errorCode":"insufficient_funds","errorMessage":"Insufficient credits for image generation","messagePattern":"Insufficient credits for image generation","errorType":"http","errorClass":"HttpError","httpStatus":402,"severity":"error","filePath":"src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts","lineNumber":188,"sourceCode":"            selectedModel.costs.output_image,\n        );\n        const estimatedOutputTextCostInCents = this.#calculateTokenCostInCents(\n            50,\n            selectedModel.costs.output,\n        ); // small text overhead estimate\n        const estimatedOutputCostInCents =\n            estimatedOutputImageCostInCents + estimatedOutputTextCostInCents;\n\n        const estimatedTotalCostInMicroCents = this.#toMicroCents(\n            estimatedInputCostInCents + estimatedOutputCostInCents,\n        );\n        const usageAllowed = await this.#meteringService.hasEnoughCredits(\n            actor,\n            estimatedTotalCostInMicroCents,\n        );\n\n        if (!usageAllowed) {\n            throw new HttpError(\n                402,\n                'Insufficient credits for image generation',\n                { legacyCode: 'insufficient_funds' },\n            );\n        }\n\n        // --- API call ---\n        const contents = this.#buildContents(\n            prompt,\n            input_images,\n            input_image_mime_type,\n        );\n        const aspectRatio = `${ratio.w}:${ratio.h}`;\n\n        const imageConfig: Record<string, string> = { aspectRatio };\n        if (quality && selectedModel.allowedQualityLevels?.includes(quality)) {\n            imageConfig.imageSize = quality;\n        }","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts#L170-L206","documentation":"Thrown by GeminiImageProvider.generate() (GeminiImageProvider.ts:188) on the generateContent path after #meteringService.hasEnoughCredits() returns false for the pre-flight cost estimate. The estimate sums input token cost (prompt + estimated image-input tokens), output image token cost, and a small output text overhead, converts to microCents, and checks the actor's balance. HTTP 402 with legacyCode insufficient_funds.","triggerScenarios":"A user with zero or near-zero credit balance calling generate(); a very expensive model (e.g. gemini-3-pro-image-preview at 4K) whose estimate exceeds remaining credits; a fresh account that has not been granted credits; a user who exhausted credits on prior calls.","commonSituations":"New trial users hitting a high-tier model; cost estimate being conservative (it overestimates to be safe) causing rejection when actual cost would fit; metering service returning a stale balance.","solutions":["Top up the actor's credit balance or grant credits via the metering/billing system.","Switch to a cheaper model or lower quality tier (e.g. gemini-2.5-flash-image, 1K instead of 4K).","Retry after confirming the balance reflects recent payments — the estimate may have been based on a stale balance.","Check hasEnoughCredits logic and the actor's current usage to confirm the rejection is correct."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const estimate = await meteringService.hasEnoughCredits(actor, estimatedCostMicroCents);\nif (!estimate) {\n  // prompt user to top up before calling generate\n}","typeGuard":null,"tryCatchPattern":"try {\n  await provider.generate(params);\n} catch (e) {\n  if (e instanceof HttpError && e.status_code === 402) {\n    // surface 'insufficient credits' to the user, offer top-up or cheaper model\n  }\n  throw e;\n}","preventionTips":["Check the actor's credit balance via meteringService before calling generate for expensive models.","Default to cheaper models/tiers when balance is unknown or low.","Surface top-up flows proactively when balance is near zero."],"tags":["billing","credits","gemini","ai-image","insufficient-funds","payment"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}