{"record":{"id":"dca400000a7e8c8f","repo":"HeyPuter/puter","slug":"unauthorized-dca400","errorCode":"unauthorized","errorMessage":"actor not found in context","messagePattern":"actor not found in context","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"critical","filePath":"src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts","lineNumber":279,"sourceCode":"        if (!url) {\n            throw new HttpError(\n                400,\n                'Failed to extract image URL from Gemini response',\n                { legacyCode: 'unknown_error' },\n            );\n        }\n\n        return url;\n    }\n\n    async #generateWithImagen(\n        prompt: string,\n        selectedModel: IGeminiImageModel,\n        params: IGenerateParams,\n    ): Promise<string> {\n        const actor = Context.get('actor');\n        if (!actor) {\n            throw new HttpError(401, 'actor not found in context', {\n                legacyCode: 'unauthorized',\n            });\n        }\n        const costCents = selectedModel.costs?.['per-image'];\n        if (costCents === undefined) {\n            throw new HttpError(\n                400,\n                `No per-image cost configured for model '${selectedModel.id}'`,\n                { legacyCode: 'bad_request' },\n            );\n        }\n        const costInMicroCents = Math.ceil(costCents * 1_000_000);\n\n        const usageAllowed = await this.#meteringService.hasEnoughCredits(\n            actor,\n            costInMicroCents,\n        );\n        if (!usageAllowed) {","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts#L261-L297","documentation":"Thrown by GeminiImageProvider.#generateWithImagen() (GeminiImageProvider.ts:279) when Context.get('actor') is falsy. The Imagen (generateImages) path requires the actor to bill per-image usage, so a missing actor is fatal before any cost or API call. This indicates the request is not executing within the AsyncLocalStorage context that sets `actor` — typically a wiring/middleware problem, not an end-user error. HTTP 401 unauthorized.","triggerScenarios":"Calling #generateWithImagen (via generate() with a model whose apiType is 'generateImages') outside of a request lifecycle that populates Context; a background job or test harness invoking the provider without running Context.run(); middleware ordering that reads actor before it is set; a code path that bypasses the standard controller context setup.","commonSituations":"Unit/integration tests calling the provider directly without setupPuterTestEnv() or Context.run({actor}, ...); a refactored controller that lost the ALS context propagation; a cron/internal task invoking image generation without establishing an actor.","solutions":["Ensure the provider is only called within a request context that sets actor via Context (the controller layer normally does this).","In tests, wrap the call: `await Context.run({ actor: testActor }, async () => provider.generate(...))` or use setupPuterTestEnv().","Verify the controller/driver middleware sets Context actor before delegating to the provider.","If calling from a background job, explicitly establish an actor in the context before invoking generate()."],"exampleFix":"// before (test or background path — actor missing)\nawait provider.generate({ prompt: 'x', model: 'imagen-4.0-fast-generate-001' });\n\n// after\nimport { Context } from '../../core/context.js';\nawait Context.run({ actor: testActor }, async () => {\n  await provider.generate({ prompt: 'x', model: 'imagen-4.0-fast-generate-001' });\n});","handlingStrategy":"validation","validationCode":"import { Context } from '../../core/context.js';\nfunction ensureActor(): Actor {\n  const actor = Context.get('actor');\n  if (!actor) throw new Error('actor not found in context — wrap call in Context.run');\n  return actor;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always invoke providers within a request context that sets actor (controllers do this).","In tests, use Context.run({ actor }, ...) or setupPuterTestEnv().","Never call provider.generate() from a bare top-level script without establishing context."],"tags":["auth","context","als","gemini","ai-image","unauthorized","wiring"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}