HeyPuter/puter · error · HttpError
App not found
Error message
App not found
What it means
Thrown by capSecondsToRemainingCredits when its `actor` parameter is falsy. This helper clamps the requested clip duration to what the actor's remaining credit can buy, so it must read metering.getRemainingUsage(actor). No actor means the call cannot be metered or clamped, so it refuses with 401 rather than silently producing unbilled output.
Source
Thrown at extensions/appTelemetry.ts:125
Array<{ user: string; user_uuid: string; user_email?: string | null }>
> {
if (!app_uuid) throw new HttpError(400, 'Missing `app_uuid`');
const safeLimit = parseIntParam(limit, {
key: 'limit',
min: 1,
max: MAX_LIMIT,
fallback: DEFAULT_LIMIT,
});
const safeOffset = parseIntParam(offset, {
key: 'offset',
min: 0,
max: MAX_OFFSET,
fallback: 0,
});
const app = await this.stores.app.getByUid(app_uuid);
if (!app) throw new HttpError(404, 'App not found');
// The `apps-of-user:<uuid>:write` implicator keys on the owner's
// UUID, not the numeric id. Look up the owner explicitly — the raw
// app row only carries `owner_user_id`. (v1 got the owner for free
// because its entity-storage layer eager-joined the owner row.)
const ownerId = (app as { owner_user_id?: number }).owner_user_id;
if (!ownerId) throw new HttpError(404, 'App owner not found');
const owner = await this.stores.user.getById(ownerId);
if (!owner?.uuid) throw new HttpError(404, 'App owner not found');
const actor = Context.get('actor');
if (!actor) throw new HttpError(401, 'Authentication required');
const ownsApp = await this.services.permission
.check(actor as Actor, `apps-of-user:${owner.uuid}:write`)
.catch(() => false);
if (!ownsApp) throw new HttpError(403, 'Permission denied');
const appId = (app as { id: number }).id;View on GitHub (pinned to 908ec23eda)
Solutions
- Route the call through the normal authenticated controller/middleware so Context.actor is set.
- If invoking capSecondsToRemainingCredits directly, pass the actor explicitly from Context.get('actor') and assert it is present first.
- In tests, use setupPuterTestEnv() / a stub Context actor rather than calling the helper bare.
- Audit the calling endpoint's RouteOptions to confirm the auth gate is enabled.
Example fix
// before — called without actor context
const allowed = await capSecondsToRemainingCredits({
metering, actor: undefined, perSecondMicroCents, requestedSeconds: durationSeconds,
});
// after — require actor up front
const actor = Context.get('actor');
if (!actor) throw new HttpError(401, 'Authentication required', { legacyCode: 'unauthorized' });
const allowed = await capSecondsToRemainingCredits({
metering, actor, perSecondMicroCents, requestedSeconds: durationSeconds,
}); Defensive patterns
Strategy: validation
Validate before calling
const actor = Context.get('actor');
if (!actor) throw new HttpError(401, 'Authentication required', { legacyCode: 'unauthorized' });
const allowed = await capSecondsToRemainingCredits({ metering, actor, perSecondMicroCents, requestedSeconds }); Type guard
function hasActor(ctx) {
const a = ctx.get('actor');
return !!a && (typeof a === 'object') && ('id' in a || 'user' in a);
} Prevention
- Always invoke generation through authenticated routes that populate Context.actor.
- In tests, use setupPuterTestEnv() or a stub actor instead of calling the helper bare.
- Treat a missing actor as a wiring defect, not a runtime retry condition.
When it happens
Trigger: The provider's generate() flow calls capSecondsToRemainingCredits without threading an actor through (or Context.get('actor') returned undefined at the call site). Typically a wiring bug: a new code path, internal batch job, or test harness that bypassed the auth middleware.
Common situations: Refactor that calls the cap helper from a background queue without populating Context; unit test that constructs the provider directly; an admin/internal route registered without the auth RouteOptions gate.
Related errors
- Invalid orderBy. Allowed: ${ALLOWED_ORDER_BY.join(', ')}
- ${key} must be an integer between ${min} and ${max}
- Missing `app_uuid`
- App owner not found
- Authentication required
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/50a934befb3e97ed.
Report an issue: GitHub.