HeyPuter/puter · error · HttpError
Invalid orderBy. Allowed: ${ALLOWED_ORDER_BY.join(', ')}
Error message
Invalid orderBy. Allowed: ${ALLOWED_ORDER_BY.join(', ')} What it means
TogetherVideoProvider reads `Context.get('actor')` before the credit check. The actor is required both to call hasEnoughCredits and later to incrementUsage on the actor. If the actor is absent, the request reached the provider without authentication context and the driver throws 401 unauthorized rather than producing unbilled output.
Source
Thrown at extensions/installedApps.ts:33
] as const;
const ORDER_BY_FIELD_MAP: Record<string, string> = {
id: 'apps.id',
name: 'apps.name',
uid: 'apps.uid',
title: 'apps.title',
installed_at: 'installed_at',
};
export const handleInstalledApps = async (
req: Request,
res: Response,
): Promise<void> => {
const actor = Context.get('actor');
if (!actor?.user?.id) throw new HttpError(401, 'Authentication required');
const orderBy = String(req.query.orderBy ?? 'installed_at');
if (!(ALLOWED_ORDER_BY as readonly string[]).includes(orderBy)) {
throw new HttpError(
400,
`Invalid orderBy. Allowed: ${ALLOWED_ORDER_BY.join(', ')}`,
);
}
const page = Math.max(Number(req.query.page) || 1, 1);
const limit = Math.min(Math.max(Number(req.query.limit) || 100, 1), 100);
const offset = (page - 1) * limit;
const orderByField = ORDER_BY_FIELD_MAP[orderBy];
const sortDirection = req.query.desc ? 'DESC' : 'ASC';
const installedApps = (await clients.db.read(
`SELECT
apps.name,
apps.uid,
apps.title,
apps.description,
apps.icon,View on GitHub (pinned to 908ec23eda)
Solutions
- Route generation through an authenticated controller/driver method.
- Assert Context.actor is set before invoking the provider; fail fast with 401 if not.
- Add a regression test asserting unauthenticated calls return 401.
- Mirror the auth/subdomain RouteOptions used by the other video providers.
Example fix
// before — driver route without auth
extension.post('/drivers/ai-video/together', (req, res) => together.generate(req.body));
// after — auth gate populates Context.actor
extension.post('/drivers/ai-video/together', { auth: true }, (req, res) => together.generate(req.body)); Defensive patterns
Strategy: try-catch
Validate before calling
// client side
if (!puter.auth.isSignedIn()) { redirectToLogin(); return; }
await puter.ai.txt2video({ prompt, model: 'together/...' }); Try / catch
try { await puter.ai.txt2video(params); }
catch (e) {
if (e?.code === 'unauthorized') { await puter.auth.signIn(); return; }
throw e;
} Prevention
- Register Together video routes with the auth gate.
- Add a regression test for unauthenticated 401.
- Never invoke the provider from a Context-less background path.
When it happens
Trigger: The Together generate route is hit without the auth gate, or the provider is invoked from a path (background job, test, miswired extension) that never populated Context.actor.
Common situations: Extension route missing `auth: true`; refactor that relocated the generate call outside the authenticated controller; test harness that instantiates the provider directly.
Related errors
- App not found
- Authentication required
- ${key} must be an integer between ${min} and ${max}
- Missing `app_uuid`
- App owner not found
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/c5e146c8d0f80bf4.
Report an issue: GitHub.