{"record":{"id":"a620b3f70bf6009f","repo":"danny-avila/LibreChat","slug":"no-tts-schema-is-set-did-you-configure-tts-in-the","errorCode":null,"errorMessage":"No TTS schema is set. Did you configure TTS in the custom config (librechat.yaml)?","messagePattern":"No TTS schema is set\\. Did you configure TTS in the custom config \\(librechat\\.yaml\\)\\?","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/server/services/Files/Audio/TTSService.js","lineNumber":51,"sourceCode":"   * @static\n   * @async\n   * @returns {Promise<TTSService>} The TTSService instance.\n   * @throws {Error} If the custom config is not found.\n   */\n  static async getInstance() {\n    return new TTSService();\n  }\n\n  /**\n   * Retrieves the configured TTS provider.\n   * @param {AppConfig | null | undefined} [appConfig] - The app configuration object.\n   * @returns {string} The name of the configured provider.\n   * @throws {Error} If no provider is set or multiple providers are set.\n   */\n  getProvider(appConfig) {\n    const ttsSchema = appConfig?.speech?.tts;\n    if (!ttsSchema) {\n      throw new Error(\n        'No TTS schema is set. Did you configure TTS in the custom config (librechat.yaml)?',\n      );\n    }\n    const providers = Object.entries(ttsSchema).filter(\n      ([key, value]) => key !== 'allowedAddresses' && Object.keys(value).length > 0,\n    );\n\n    if (providers.length !== 1) {\n      throw new Error(\n        providers.length > 1\n          ? 'Multiple providers are set. Please set only one provider.'\n          : 'No provider is set. Please set a provider.',\n      );\n    }\n    return providers[0][0];\n  }\n\n  /**","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/Files/Audio/TTSService.js#L33-L69","documentation":"TTSService.getProvider throws when appConfig.speech.tts is falsy. The TTS subsystem reads its wiring from the `speech.tts` block resolved via getAppConfig (typically librechat.yaml). An absent or empty block means no provider can be selected.","triggerScenarios":"Any TTS request (POST /api/speech/tts) when librechat.yaml has no `speech.tts` section, or role/tenant-scoped config returns an object whose `speech.tts` is undefined/null.","commonSituations":"TTS enabled in the client but never configured server-side; librechat.yaml not mounted; config key renamed during an upgrade; tenant override returns empty speech.","solutions":["Add a `speech.tts` block with exactly one populated provider (openai, azureOpenAI, elevenlabs, or localai) to librechat.yaml.","Confirm librechat.yaml is mounted and parsed (startup log).","Restart the API server so getAppConfig reloads."],"exampleFix":"# before\nspeech: {}\n\n# after (librechat.yaml)\nspeech:\n  tts:\n    openai:\n      apiKey: '${TTS_API_KEY}'\n      model: 'tts-1'\n      voices: ['alloy', 'echo']","handlingStrategy":"validation","validationCode":"const appConfig = await getAppConfig({ role, userId, tenantId });\nconst tts = appConfig?.speech?.tts;\nif (!tts) {\n  return res.status(503).json({ error: 'TTS is not configured on this server.' });\n}","typeGuard":"/** @param {unknown} c */\nfunction hasTtsSchema(c) {\n  return !!c && typeof c === 'object' && 'speech' in c\n    && !!c.speech && typeof c.speech === 'object'\n    && 'tts' in c.speech && !!c.speech.tts\n    && typeof c.speech.tts === 'object';\n}","tryCatchPattern":null,"preventionTips":["Gate TTS routes on the presence of the speech.tts block.","Mount and validate librechat.yaml at startup.","Add a CI config assertion for the expected speech.tts shape."],"tags":["tts","config","librechat-yaml","schema"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}