HeyPuter/puter · critical · HttpError

unauthorized

unauthorized

Error message

Authentication required

What it means

The abstract SpeechToTextProvider base exposes requireActor(), called by each concrete provider before transcribing/translating. It reads Context.get('actor') and throws 401 / unauthorized if absent. Same in-depth auth gate as the voice driver, centralised so every STT provider (OpenAI, xAI) inherits it without re-implementing the check.

Source

Thrown at src/backend/drivers/ai-speech2txt/providers/SpeechToTextProvider.ts:58

    abstract listModels(): Promise<ISpeechToTextModel[]>;

    abstract transcribe(args: ITranscribeArgs): Promise<unknown>;

    /**
     * Translate to English. Providers whose upstream has no separate
     * translation endpoint override this to delegate to `transcribe`.
     */
    abstract translate(args: ITranscribeArgs): Promise<unknown>;

    getReportedCosts(): Record<string, unknown>[] {
        return [];
    }

    /** The authenticated caller, or a 401 if the request carries none. */
    protected requireActor(): Actor {
        const actor = Context.get('actor') as Actor | undefined;
        if (!actor)
            throw new HttpError(401, 'Authentication required', {
                legacyCode: 'unauthorized',
            });
        return actor;
    }

    /** Reject the call unless the caller supplied audio. */
    protected requireFile(args: ITranscribeArgs): void {
        if (!args.file)
            throw new HttpError(400, '`file` is required', {
                legacyCode: 'bad_request',
            });
    }
}

View on GitHub (pinned to 908ec23eda)

Solutions

  1. Run the call inside an authenticated request so the actor is on the ALS Context.
  2. In tests use setupPuterTestEnv() and hit the real route so the actor is populated.
  3. Ensure the controller declares auth in its RouteOptions.
Defensive patterns

Strategy: validation

Validate before calling

// client-side (puter.js)
if (!puter.auth.isSignedIn()) await puter.auth.signIn();

Try / catch

try {
  await puter.ai.speech2txt(/* ... */);
} catch (e) {
  if (e?.code === 'unauthorized' || e?.status === 401) await reAuthenticate();
  else throw e;
}

Prevention

When it happens

Trigger: A provider's transcribe/translate running outside an authenticated ALS Context: a background job, a test calling the provider class directly, or a controller route missing the auth gate.

Common situations: A unit test instantiating OpenAISpeechToTextProvider and calling transcribe without seeding the Context; a controller route that forgot the auth RouteOptions.

Understand the failure class

Related errors


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