{"record":{"id":"fe5563fd48c9ea28","repo":"HeyPuter/puter","slug":"insufficient-funds-fe5563","errorCode":"insufficient_funds","errorMessage":"Insufficient credits for image generation","messagePattern":"Insufficient credits for image generation","errorType":"http","errorClass":"HttpError","httpStatus":402,"severity":"warning","filePath":"src/backend/drivers/ai-image/providers/together/TogetherImageProvider.ts","lineNumber":159,"sourceCode":"            const centsPerMP = selectedModel.costs['1MP'];\n            if (centsPerMP === undefined) {\n                throw new Error(`Model ${selectedModel.id} missing '1MP' cost`);\n            }\n            const MP = (ratio.h * ratio.w) / 1_000_000;\n            costInMicroCents = centsPerMP * MP * 1_000_000;\n            usageAmount = MP;\n            usageKey = '1MP';\n        }\n\n        const usageType = `${selectedModel.id}:${usageKey}`;\n\n        const usageAllowed = await this.#meteringService.hasEnoughCredits(\n            actor,\n            costInMicroCents,\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        // Resolve abstract aspect ratios (e.g. 1:1, 16:9) to concrete pixel\n        // dimensions via the model's own resolution_map.\n        let resolvedRatio = ratio;\n        if (\n            pricingUnit === 'per-tier' &&\n            quality &&\n            selectedModel.resolution_map\n        ) {\n            const ratioKey = `${ratio.w}:${ratio.h}`;\n            const resolutionEntry =\n                selectedModel.resolution_map[ratioKey]?.[quality];\n            if (resolutionEntry) {","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/together/TogetherImageProvider.ts#L141-L177","documentation":"The Together image provider checks the user's credit balance via meteringService.hasEnoughCredits() before making the paid upstream API call. The estimated cost is computed from the model's pricing (per-image, per-tier, or per-megapixel). If the user's balance is insufficient, this error prevents the call to Together AI and avoids unbilled usage.","triggerScenarios":"The authenticated user's credit balance is lower than the computed costInMicroCents for the requested model and resolution. This is a per-request check; each generation call is gated independently.","commonSituations":"A free-tier user who has exhausted their credits; a user on a paid plan whose balance hasn't been topped up; calling a high-cost model (e.g. 2K or 4K resolution) with minimal remaining credits.","solutions":["Top up the user's credit balance through the billing system.","Use a lower-cost model or lower resolution tier to reduce the per-request cost.","Check the user's balance via the metering API before attempting generation and display a top-up prompt.","Use test_mode: true for development/testing to bypass the credit check."],"exampleFix":"// before — calling without checking balance\nconst url = await provider.generate({ prompt: 'a cat', model: 'togetherai:expensive-model' });\n\n// after — use test_mode for dev, or catch the 402\ntry {\n  const url = await provider.generate({ prompt: 'a cat', model: 'togetherai:black-forest-labs/FLUX.1-schnell' });\n} catch (e) {\n  if (e.code === 'insufficient_funds') {\n    // prompt user to top up credits\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Check balance before generation if a metering client is available\nconst balance = await meteringService.getUserBalance(actor);\nconst estimatedCost = estimateTogetherCost(selectedModel, ratio, quality);\nif (balance < estimatedCost) {\n  throw new Error('Insufficient credits — please top up your balance');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const url = await provider.generate(params);\n} catch (e) {\n  if (e.legacyCode === 'insufficient_funds' || e.code === 'insufficient_funds') {\n    // Show top-up prompt to user\n    showTopUpDialog();\n  } else {\n    throw e;\n  }\n}","preventionTips":["Check the user's credit balance via the metering API before attempting generation.","Use test_mode: true in development to bypass the credit check.","Choose lower-cost models or resolutions when credits are low."],"tags":["together","billing","credits","insufficient-funds","image-generation"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}