{"record":{"id":"1d323dba97e9b2c9","repo":"HeyPuter/puter","slug":"unauthorized-1d323d","errorCode":"unauthorized","errorMessage":"actor not found in context","messagePattern":"actor not found in context","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"error","filePath":"src/backend/drivers/ai-image/providers/cloudflare/CloudflareImageProvider.ts","lineNumber":104,"sourceCode":"    async generate(params: IGenerateParams): Promise<string> {\n        const options = params as CloudflareGenerateParams;\n        const { prompt, test_mode } = options;\n        const ratio = this.#normalizeRatio(options.ratio);\n        const selectedModel = this.#getModel(options.model);\n\n        if (test_mode) {\n            return 'https://puter-sample-data.puter.site/image_example.png';\n        }\n\n        if (typeof prompt !== 'string' || prompt.trim().length === 0) {\n            throw new HttpError(400, '`prompt` must be a non-empty string', {\n                legacyCode: 'bad_request',\n            });\n        }\n\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\n        // Canonical `input_images`/`input_image` → Cloudflare's `image` field.\n        // Cloudflare accepts a single input image; a URL is fetched to base64\n        // server-side (SSRF-guarded) since the API has no URL field.\n        const singleInput = resolveSingleInputImage(options, 'Cloudflare');\n        if (singleInput) {\n            options.image ??= isHttpUrl(singleInput)\n                ? (await fetchImageAsBase64(singleInput)).base64\n                : singleInput;\n        }\n\n        const steps = this.#resolveSteps(selectedModel, options);\n        const costComponents = this.#estimateCost(selectedModel, ratio, steps, {\n            hasInputImage:\n                typeof options.image === 'string' &&","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-image/providers/cloudflare/CloudflareImageProvider.ts#L86-L122","documentation":"CloudflareImageProvider.generate reads Context.get('actor'); if absent it throws HTTP 401 unauthorized ('actor not found in context'). Like the driver-level auth check, this means the call isn't running inside an authenticated request lifecycle.","triggerScenarios":"Calling CloudflareImageProvider.generate directly outside an authed request, or a code path that reaches it without the auth gate having set Context actor.","commonSituations":"Direct provider invocation in tests/scripts; a route missing the auth gate; an internal job invoking the provider without setting actor.","solutions":["Reach the provider through the authed image-generation driver/route so actor is set.","If invoking directly, set Context actor first (Context.run({ actor }, ...)).","In tests, authenticate a user via setupPuterTestEnv() before calling generate()."],"exampleFix":"// before — provider called with no actor\nawait cfProvider.generate({ prompt });\n// after — run inside an authed context\nawait Context.run({ actor }, () => cfProvider.generate({ prompt }));","handlingStrategy":"validation","validationCode":"const actor = Context.get('actor');\nif (!actor) throw new Error('CloudflareImageProvider.generate requires an authed actor');","typeGuard":"function hasActor(ctx) {\n  const a = ctx.get('actor');\n  return !!a && typeof a === 'object';\n}","tryCatchPattern":null,"preventionTips":["Reach the provider through the authed image-generation driver/route.","Set Context actor when invoking the provider directly.","Authenticate a user in tests before calling generate()."],"tags":["ai-image","cloudflare","authentication","actor","unauthorized"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}