{"record":{"id":"addacc3aec12764f","repo":"HeyPuter/puter","slug":"insufficient-funds-addacc","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/openai/OpenAiImageProvider.ts","lineNumber":192,"sourceCode":"                    estimatedPromptTokenCount + estimatedImageInputTokens,\n                inputTextTokens: estimatedPromptTokenCount,\n                inputImageTokens: estimatedImageInputTokens,\n                cachedInputTokens: 0,\n                cachedInputTextTokens: 0,\n                cachedInputImageTokens: 0,\n            } as OpenAIImageUsage,\n        );\n        const estimatedOutputCostInCents = outputPriceInCents;\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        // With input images we use the edit endpoint (gpt-image only);\n        // otherwise the standard generate endpoint.\n        const result = hasInputImages\n            ? await this.#openai.images.edit(\n                  await this.#buildEditParams(\n                      selectedModel.id,\n                      { user: userIdentifier, prompt, size, quality },\n                      input_images!,\n                      input_image_mime_type,\n                  ),\n              )\n            : await this.#openai.images.generate(","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/openai/OpenAiImageProvider.ts#L174-L210","documentation":"Thrown by OpenAiImageProvider.generate() (OpenAiImageProvider.ts:192) when hasEnoughCredits returns false for the estimated total (input cost estimate + output price). Same insufficient-funds semantics as the Gemini equivalent but for the OpenAI provider. HTTP 402 insufficient_funds.","triggerScenarios":"Low-balance actor calling generate(); an expensive size/quality (e.g. high quality, large size) exceeding remaining credits; estimate overestimating slightly vs actual cost.","commonSituations":"Trial credits exhausted; user selected a high-cost tier; balance stale after a recent top-up.","solutions":["Top up or grant credits to the actor.","Choose a lower quality level (low instead of high) or smaller size to reduce the estimate.","Confirm the metering balance is current and retry."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!(await meteringService.hasEnoughCredits(actor, estimatedMicroCents))) {\n  // prompt top-up or cheaper tier\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; offer lower quality/size or top-up\n  }\n  throw e;\n}","preventionTips":["Pre-check balance for expensive size/quality tiers.","Default to low quality when balance is low.","Refresh balance after payments before retrying."],"tags":["billing","credits","openai","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"}