HeyPuter/puter · error · HttpError

bad_request

bad_request

Error message

Missing or invalid `interface`

What it means

Thrown by POST /drivers/call when body.interface is missing, empty, or not a string. The interface name (e.g. 'puter-chat-completion') selects which driver registry to dispatch into; without a valid one the resolver cannot start.

Source

Thrown at src/backend/controllers/drivers/DriverController.ts:239

                    key: 'user',
                },
            },
            this.#handleListInterfaces,
        );
    }

    // -- Handlers ----------------------------------------------------

    #handleCall = async (req: Request, res: Response): Promise<void> => {
        const {
            interface: ifaceName,
            method,
            driver: driverName,
            args = {},
        } = (req.body ?? {}) as Record<string, unknown>;

        if (!ifaceName || typeof ifaceName !== 'string') {
            throw new HttpError(400, 'Missing or invalid `interface`', {
                legacyCode: 'bad_request',
            });
        }
        if (!method || typeof method !== 'string') {
            throw new HttpError(400, 'Missing or invalid `method`', {
                legacyCode: 'bad_request',
            });
        }
        const requestedDriver =
            typeof driverName === 'string' ? driverName : undefined;

        const driver = this.resolve(ifaceName, requestedDriver);
        if (!driver) {
            const resolvedName = requestedDriver ?? this.getDefault(ifaceName);
            throw new HttpError(
                404,
                `Driver not found: ${ifaceName}:${resolvedName ?? '(no default)'}`,
                { legacyCode: 'not_found' },

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Send interface as a non-empty string naming a registered interface, e.g. {"interface":"puter-chat-completion", "method":"complete", "args":{...}}.
  2. Confirm the body is JSON (Content-Type: application/json) — a form-encoded or empty body yields undefined interface.
  3. If extending the SDK, centralize the interface token in a constant so it is never omitted.

Example fix

// before
{ method: 'complete', args: { prompt } }
// after
{ interface: 'puter-chat-completion', method: 'complete', args: { prompt } }
Defensive patterns

Strategy: type-guard

Validate before calling

if (typeof ifaceName !== 'string' || ifaceName.length === 0) {
  throw new Error('interface required');
}

Type guard

const isInterfaceName = (v: unknown): v is string =>
  typeof v === 'string' && v.length > 0;

Prevention

When it happens

Trigger: POST /drivers/call with no interface field, interface: 42, interface: { name:'...' }, or interface: '' (empty string is falsy and rejected by the `!ifaceName` short-circuit).

Common situations: Client building the RPC payload from an untyped object and forgetting the interface key; an SDK wrapper that names it `service` or `driver` instead of `interface`; JSON body parsed as query params so body is empty.

Related errors


AI-assisted analysis of HeyPuter/puter@908ec23eda (2026-08-12). Data as JSON: /api/errors/77d30777a2086d56. Report an issue: GitHub.