HeyPuter/puter · critical · HttpError
unauthorized
unauthorized
Error message
actor not found in context
What it means
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.
Source
Thrown at src/backend/drivers/ai-image/providers/gemini/GeminiImageProvider.ts:279
if (!url) {
throw new HttpError(
400,
'Failed to extract image URL from Gemini response',
{ legacyCode: 'unknown_error' },
);
}
return url;
}
async #generateWithImagen(
prompt: string,
selectedModel: IGeminiImageModel,
params: IGenerateParams,
): Promise<string> {
const actor = Context.get('actor');
if (!actor) {
throw new HttpError(401, 'actor not found in context', {
legacyCode: 'unauthorized',
});
}
const costCents = selectedModel.costs?.['per-image'];
if (costCents === undefined) {
throw new HttpError(
400,
`No per-image cost configured for model '${selectedModel.id}'`,
{ legacyCode: 'bad_request' },
);
}
const costInMicroCents = Math.ceil(costCents * 1_000_000);
const usageAllowed = await this.#meteringService.hasEnoughCredits(
actor,
costInMicroCents,
);
if (!usageAllowed) {View on GitHub (pinned to 908ec23eda)
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().
Example fix
// before (test or background path — actor missing)
await provider.generate({ prompt: 'x', model: 'imagen-4.0-fast-generate-001' });
// after
import { Context } from '../../core/context.js';
await Context.run({ actor: testActor }, async () => {
await provider.generate({ prompt: 'x', model: 'imagen-4.0-fast-generate-001' });
}); Defensive patterns
Strategy: validation
Validate before calling
import { Context } from '../../core/context.js';
function ensureActor(): Actor {
const actor = Context.get('actor');
if (!actor) throw new Error('actor not found in context — wrap call in Context.run');
return actor;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/dca400000a7e8c8f.
Report an issue: GitHub.