{"record":{"id":"5b43fce157c309f8","repo":"HeyPuter/puter","slug":"insufficient-funds-5b43fc","errorCode":"insufficient_funds","errorMessage":"Insufficient credits","messagePattern":"Insufficient credits","errorType":"http","errorClass":"HttpError","httpStatus":402,"severity":"warning","filePath":"src/backend/drivers/ai-ocr/OCRDriver.ts","lineNumber":272,"sourceCode":"            credentials: {\n                accessKeyId: this.#awsConfig!.accessKeyId!,\n                secretAccessKey: this.#awsConfig!.secretAccessKey!,\n            },\n            region,\n        });\n        this.#textractClients[region] = client;\n        return client;\n    }\n\n    async #textractRecognize(loaded: LoadedFile, actor: Actor) {\n        const usageType = 'aws-textract:detect-document-text:page';\n        const costPerPage = OCR_COSTS[usageType];\n        const hasCredits = await this.services.metering.hasEnoughCredits(\n            actor!,\n            costPerPage,\n        );\n        if (!hasCredits)\n            throw new HttpError(402, 'Insufficient credits', {\n                legacyCode: 'insufficient_funds',\n            });\n\n        // Prefer S3 direct source if the file is FS-backed; fall back to raw bytes.\n        const s3Info =\n            loaded.fsEntry &&\n            loaded.fsEntry.bucket &&\n            loaded.fsEntry.bucketRegion\n                ? {\n                      bucket: loaded.fsEntry.bucket,\n                      bucketRegion: loaded.fsEntry.bucketRegion,\n                      key: loaded.fsEntry.uuid,\n                  }\n                : null;\n\n        const tryRun = async (useS3: boolean) => {\n            const region =\n                s3Info && useS3","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-ocr/OCRDriver.ts#L254-L290","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Top up the user's credit balance.","Switch to the Mistral OCR provider if it has a lower per-page cost for the user's use case.","Use test_mode: true for development/testing to bypass the credit check."],"exampleFix":"// before — calling OCR without checking balance\nconst result = await driver.recognize({\n  source: 'large-doc.pdf',\n  provider: 'aws-textract',\n});\n\n// after — handle insufficient credits\ntry {\n  const result = await driver.recognize({ source: 'doc.pdf', provider: 'aws-textract' });\n} catch (e) {\n  if (e.code === 'insufficient_funds') {\n    // prompt user to top up; Textract costs $0.15/page\n  }\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check credits if metering is accessible\nconst costPerPage = 150000; // microcents for Textract\nconst balance = await meteringService.getUserBalance(actor);\nif (balance < costPerPage) {\n  throw new Error('Insufficient credits for Textract OCR ($0.15/page minimum)');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await driver.recognize({ ...args, provider: 'aws-textract' });\n} catch (e) {\n  if (e.code === 'insufficient_funds') {\n    // Prompt user to top up, or switch to a cheaper provider\n    showTopUpDialog('Textract OCR requires $0.15/page');\n  }\n}","preventionTips":["Check the user's credit balance before submitting large documents for OCR.","Warn users about the per-page cost before processing.","Use test_mode: true during development."],"tags":["ocr","aws","textract","billing","credits","insufficient-funds"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}