HeyPuter/puter · warning · HttpError

insufficient_funds

insufficient_funds

Error message

Insufficient credits

What it means

In the AWS Textract OCR path, the driver checks the user's credit balance against the per-page cost (OCR_COSTS['aws-textract:detect-document-text:page'] = 150,000 microcents = $0.15/page) before making the paid Textract API call. If the user cannot afford even one page, the call is blocked.

Source

Thrown at src/backend/drivers/ai-ocr/OCRDriver.ts:272

            credentials: {
                accessKeyId: this.#awsConfig!.accessKeyId!,
                secretAccessKey: this.#awsConfig!.secretAccessKey!,
            },
            region,
        });
        this.#textractClients[region] = client;
        return client;
    }

    async #textractRecognize(loaded: LoadedFile, actor: Actor) {
        const usageType = 'aws-textract:detect-document-text:page';
        const costPerPage = OCR_COSTS[usageType];
        const hasCredits = await this.services.metering.hasEnoughCredits(
            actor!,
            costPerPage,
        );
        if (!hasCredits)
            throw new HttpError(402, 'Insufficient credits', {
                legacyCode: 'insufficient_funds',
            });

        // Prefer S3 direct source if the file is FS-backed; fall back to raw bytes.
        const s3Info =
            loaded.fsEntry &&
            loaded.fsEntry.bucket &&
            loaded.fsEntry.bucketRegion
                ? {
                      bucket: loaded.fsEntry.bucket,
                      bucketRegion: loaded.fsEntry.bucketRegion,
                      key: loaded.fsEntry.uuid,
                  }
                : null;

        const tryRun = async (useS3: boolean) => {
            const region =
                s3Info && useS3

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Top up the user's credit balance.
  2. Switch to the Mistral OCR provider if it has a lower per-page cost for the user's use case.
  3. Use test_mode: true for development/testing to bypass the credit check.

Example fix

// before — calling OCR without checking balance
const result = await driver.recognize({
  source: 'large-doc.pdf',
  provider: 'aws-textract',
});

// after — handle insufficient credits
try {
  const result = await driver.recognize({ source: 'doc.pdf', provider: 'aws-textract' });
} catch (e) {
  if (e.code === 'insufficient_funds') {
    // prompt user to top up; Textract costs $0.15/page
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check credits if metering is accessible
const costPerPage = 150000; // microcents for Textract
const balance = await meteringService.getUserBalance(actor);
if (balance < costPerPage) {
  throw new Error('Insufficient credits for Textract OCR ($0.15/page minimum)');
}

Try / catch

try {
  const result = await driver.recognize({ ...args, provider: 'aws-textract' });
} catch (e) {
  if (e.code === 'insufficient_funds') {
    // Prompt user to top up, or switch to a cheaper provider
    showTopUpDialog('Textract OCR requires $0.15/page');
  }
}

Prevention

When it happens

Trigger: The authenticated user's credit balance is below 150,000 microcents (the Textract per-page cost). The check happens before the Textract call, so no upstream cost is incurred.

Common situations: A free-tier user with no remaining credits; a user whose balance was depleted by prior OCR jobs; large document processing where the user didn't check their balance first.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/5b43fce157c309f8. Report an issue: GitHub.