HeyPuter/puter · warning · HttpError
insufficient_funds
insufficient_funds
Error message
Insufficient credits for image generation
What it means
The xAI image provider estimates the cost of a generation (output resolution price plus per-image media input price for edits) and checks the user's credit balance before making the paid upstream call. If the estimated cost exceeds the user's remaining credits, generation is blocked. The cost scales with resolution tier (1k vs 2k) and the number of input images for edit operations.
Source
Thrown at src/backend/drivers/ai-image/providers/xai/XAIImageProvider.ts:110
const resolution = this.#normalizeResolution(quality);
const aspectRatio = this.#aspectRatio(ratio);
const actor = Context.get('actor');
const userIdentifier =
actor?.user.id + actor?.app?.uid ? `:${actor?.app?.uid}` : '';
const outputPriceInCents = selectedModel.costs[`output:${resolution}`];
const mediaInputPriceInCents = selectedModel.costs.media_input ?? 0;
const estimatedCostInCents =
outputPriceInCents +
(hasInputImages ? mediaInputPriceInCents * inputImageCount : 0);
const usageAllowed = await this.#meteringService.hasEnoughCredits(
actor,
estimatedCostInCents * 1_000_000,
);
if (!usageAllowed) {
throw new HttpError(
402,
'Insufficient credits for image generation',
{ legacyCode: 'insufficient_funds' },
);
}
const response = hasInputImages
? await this.#edit(
selectedModel.id,
prompt,
input_images!,
input_image_mime_type,
resolution,
aspectRatio,
)
: ((await this.#client.images.generate({
model: selectedModel.id,
prompt,View on GitHub (pinned to 908ec23eda)
Solutions
- Top up the user's credit balance.
- Use a lower resolution tier (quality: '1k' instead of '2k') to reduce cost.
- Reduce the number of input images for edit operations.
- Use test_mode: true for development to bypass the credit check.
Example fix
// before — requesting 2k with multiple input images
const url = await provider.generate({
prompt: 'edit this',
quality: '2k',
input_images: ['img1.jpg', 'img2.jpg', 'img3.jpg'],
});
// after — use 1k to reduce cost, or catch the error
try {
const url = await provider.generate({ prompt: 'edit this', quality: '1k', input_images: ['img1.jpg'] });
} catch (e) {
if (e.code === 'insufficient_funds') {
// prompt user to add credits or downgrade resolution
}
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check balance if metering is accessible
const estimatedCost = computeXaiCost(model, quality, inputImages?.length);
const balance = await meteringService.getUserBalance(actor);
if (balance < estimatedCost) {
throw new Error('Insufficient credits for this generation');
} Try / catch
try {
const url = await provider.generate(params);
} catch (e) {
if (e.legacyCode === 'insufficient_funds' || e.code === 'insufficient_funds') {
// Prompt user to top up, or retry with quality: '1k'
params.quality = '1k';
const url = await provider.generate(params);
} else {
throw e;
}
} Prevention
- Use quality: '1k' instead of '2k' when credits are low.
- Limit the number of input images for edit operations to reduce cost.
- Use test_mode: true during development.
When it happens
Trigger: The user's credit balance is below the estimated cost, which is computed as outputPriceInCents (from costs['output:1k'] or costs['output:2k']) plus mediaInputPriceInCents * inputImageCount when editing with input images.
Common situations: A user with low credits attempting a 2k resolution generation (more expensive than 1k); editing multiple input images (each adds media_input cost); a free-tier user who has exhausted their allowance.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/0ef3d01836b24ae6.
Report an issue: GitHub.