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

  1. Top up the user's credit balance.
  2. Use a lower resolution tier (quality: '1k' instead of '2k') to reduce cost.
  3. Reduce the number of input images for edit operations.
  4. 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

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.