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

  1. Pass a plain object: puter.apps.create({ name, index_url, ... }).
  2. On the server, JSON-parse and type-check req.body before invoking create().
  3. Confirm Content-Type: application/json is set on the request.
  4. 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

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.