HeyPuter/puter · error · HttpError
appId parameter is required
Error message
appId parameter is required
What it means
AppDriver.create requires an `object` argument carrying the new app's fields. The very first check rejects when object is falsy or not an object type. This runs before actor/permission validation, so a malformed request body fails fast with 400 bad_request before any auth or dedupe logic.
Source
Thrown at extensions/metering.ts:75
const actor = Context.get('actor');
if (!actor?.user) throw new HttpError(401, 'Authentication required');
const [actorUsage, allowanceInfo] = await Promise.all([
services.metering.getActorCurrentMonthUsageDetails(actor),
services.metering.getAllowedUsage(actor),
]);
res.json({ ...actorUsage, allowanceInfo });
};
export const handleMeteringUsageForApp = async (
req: Request,
res: Response,
): Promise<void> => {
const actor = Context.get('actor');
if (!actor?.user) throw new HttpError(401, 'Authentication required');
let appId = String(req.params.appIdOrName ?? '');
if (!appId) throw new HttpError(400, 'appId parameter is required');
// If not a UUID-shaped app UID, look up by name
if (!appId.startsWith('app-')) {
const appRows = (await clients.db.read(
'SELECT `uid` FROM `apps` WHERE `name` = ? LIMIT 1',
[appId],
)) as Array<{ uid: string }>;
if (appRows.length > 0) {
appId = appRows[0].uid;
} else {
throw new HttpError(404, 'App not found');
}
}
const appUsage =
await services.metering.getActorCurrentMonthAppUsageDetails(
actor,
appId,View on GitHub (pinned to 908ec23eda)
Solutions
- Pass a plain object: puter.apps.create({ name, index_url, ... }).
- On the server, JSON-parse and type-check req.body before invoking create().
- Confirm Content-Type: application/json is set on the request.
- Cross-check the call signature against the puter.js Apps module.
Example fix
// before
puter.apps.create();
puter.apps.create('my-app');
puter.apps.create({ name: 'my-app' }, null);
// after
puter.apps.create({ name: 'my-app', index_url: 'https://my.app/' }); Defensive patterns
Strategy: type-guard
Validate before calling
function isPlainObject(v) { return v != null && typeof v === 'object' && !Array.isArray(v); }
if (!isPlainObject(appFields)) throw new Error('create() requires an object');
await puter.apps.create(appFields); Type guard
function isAppCreateObject(v) {
return v != null && typeof v === 'object' && !Array.isArray(v) && typeof v.name === 'string';
} Prevention
- Send Content-Type: application/json and a JSON object body.
- Pass the fields object as the first arg, options as the second.
- Unit-test the client serializer to confirm it emits an object, not a query string.
When it happens
Trigger: Calling puter.apps.create() with no arguments, with only options and no object, or with a non-object payload (string, array, number) as the first arg. Typically a serialization bug or a wrong call signature in the client.
Common situations: Client serialized the form as a query string instead of JSON; positional-arg confusion (passing the name string where the object belongs); SDK misuse where create() was called with only an options bag.
Related errors
AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12).
Data as JSON: /api/errors/a541a1fcbc4215ae.
Report an issue: GitHub.