{"record":{"id":"ff206ac2a7bf885b","repo":"HeyPuter/puter","slug":"unauthorized-ff206a","errorCode":"unauthorized","errorMessage":"Authentication required","messagePattern":"Authentication required","errorType":"http","errorClass":"HttpError","httpStatus":401,"severity":"error","filePath":"src/backend/drivers/ai-tts/TTSDriver.ts","lineNumber":156,"sourceCode":"                    if (Array.isArray(entries)) all.push(...entries);\n                } catch {\n                    // ignore — cost reporting is best-effort\n                }\n            }\n        }\n        return all;\n    }\n\n    /**\n     * Synthesize speech from text, routed to the provider named by `provider`\n     * (or the default when none is given).\n     */\n    async synthesize(\n        args: ISynthesizeArgs,\n    ): Promise<DriverStreamResult | { url: string; content_type: string }> {\n        const actor = Context.get('actor');\n        if (!actor)\n            throw new HttpError(401, 'Authentication required', {\n                legacyCode: 'unauthorized',\n            });\n\n        const providerName = this.#resolveProvider(args);\n        const provider = this.#providers[providerName];\n        if (!provider) {\n            throw new HttpError(\n                400,\n                `TTS provider not configured: ${providerName}. Available: ${Object.keys(this.#providers).join(', ')}`,\n                { legacyCode: 'bad_request' },\n            );\n        }\n\n        return provider.synthesize(\n            this.#providerArgs(providerName, args),\n        ) as Promise<\n            DriverStreamResult | { url: string; content_type: string }\n        >;","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/HeyPuter/puter/blob/908ec23eda38526170322c3edf71ba45ecb1ca95/src/backend/drivers/ai-tts/TTSDriver.ts#L138-L174","documentation":"TTSDriver.synthesize reads the authenticated actor from the request Context (ALS). If no actor is set — meaning the call did not pass an auth gate — it throws HTTP 401 (legacyCode unauthorized) before any provider routing. This guard ensures only authenticated sessions synthesize speech.","triggerScenarios":"Invoking the puter-tts synthesize driver/route without a valid authenticated session, or calling TTSDriver.synthesize programmatically outside a request scope where Context.get('actor') was never populated.","commonSituations":"A route registered without the auth RouteOptions gate; a SDK call missing the auth token; server-internal code calling synthesize without establishing actor context; a token that expired mid-session.","solutions":["Ensure the caller is authenticated: pass a valid user/app token with the request.","If invoking from backend code, populate Context with the actor (actor set in ALS) before calling synthesize.","Confirm the route/driver path is behind the auth gate in its RouteOptions.","Re-authenticate the user if the session expired."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Ensure an authenticated session exists before calling synthesize.\nif (!puter.auth?.token && !sessionToken) {\n  // redirect to sign-in / obtain a token\n  return;\n}\nawait driver.synthesize({ text: 'hi' });","typeGuard":null,"tryCatchPattern":"try {\n  await driver.synthesize({ text: 'hi' });\n} catch (e) {\n  if (e?.status === 401 || e?.fields?.legacyCode === 'unauthorized') {\n    // re-authenticate the user, then retry\n  } else throw e;\n}","preventionTips":["Register the TTS route behind the auth gate in its RouteOptions.","When calling TTSDriver from backend code, populate Context actor first.","Handle token expiry client-side and re-auth before retrying."],"tags":["auth","tts","unauthorized","context"],"backgroundTag":null,"analyzedSha":"908ec23eda38526170322c3edf71ba45ecb1ca95","analyzedAt":"2026-08-12T20:53:15.911Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}