{"record":{"id":"60738a043662a570","repo":"HeyPuter/puter","slug":"unauthorized-60738a","errorCode":"unauthorized","errorMessage":"Authentication required","messagePattern":"Authentication required","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"critical","filePath":"src/backend/drivers/ai-speech2txt/providers/SpeechToTextProvider.ts","lineNumber":58,"sourceCode":"    abstract listModels(): Promise<ISpeechToTextModel[]>;\n\n    abstract transcribe(args: ITranscribeArgs): Promise<unknown>;\n\n    /**\n     * Translate to English. Providers whose upstream has no separate\n     * translation endpoint override this to delegate to `transcribe`.\n     */\n    abstract translate(args: ITranscribeArgs): Promise<unknown>;\n\n    getReportedCosts(): Record<string, unknown>[] {\n        return [];\n    }\n\n    /** The authenticated caller, or a 401 if the request carries none. */\n    protected requireActor(): Actor {\n        const actor = Context.get('actor') as Actor | undefined;\n        if (!actor)\n            throw new HttpError(401, 'Authentication required', {\n                legacyCode: 'unauthorized',\n            });\n        return actor;\n    }\n\n    /** Reject the call unless the caller supplied audio. */\n    protected requireFile(args: ITranscribeArgs): void {\n        if (!args.file)\n            throw new HttpError(400, '`file` is required', {\n                legacyCode: 'bad_request',\n            });\n    }\n}\n","sourceCodeStart":40,"sourceCodeEnd":72,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-speech2txt/providers/SpeechToTextProvider.ts#L40-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"A unit test instantiating OpenAISpeechToTextProvider and calling transcribe without seeding the Context; a controller route that forgot the auth RouteOptions.","solutions":["Run the call inside an authenticated request so the actor is on the ALS Context.","In tests use setupPuterTestEnv() and hit the real route so the actor is populated.","Ensure the controller declares auth in its RouteOptions."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// client-side (puter.js)\nif (!puter.auth.isSignedIn()) await puter.auth.signIn();","typeGuard":null,"tryCatchPattern":"try {\n  await puter.ai.speech2txt(/* ... */);\n} catch (e) {\n  if (e?.code === 'unauthorized' || e?.status === 401) await reAuthenticate();\n  else throw e;\n}","preventionTips":["Gate every user-scoped AI call behind a session check.","Don't call provider classes directly outside the request pipeline.","In tests, use setupPuterTestEnv() rather than instantiating providers raw."],"tags":["auth","authentication","context","speech2txt"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}