{"record":{"id":"39513a627957f240","repo":"danny-avila/LibreChat","slug":"voice-voice-is-not-available","errorCode":null,"errorMessage":"Voice ${voice} is not available.","messagePattern":"Voice (.+?) is not available\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"api/server/services/Files/Audio/TTSService.js","lineNumber":119,"sourceCode":"\n  /**\n   * Prepares the request for OpenAI TTS provider.\n   * @param {Object} ttsSchema - The TTS schema for OpenAI.\n   * @param {string} input - The input text.\n   * @param {string} voice - The selected voice.\n   * @returns {Array} An array containing the URL, data, and headers for the request.\n   * @throws {Error} If the selected voice is not available.\n   */\n  openAIProvider(ttsSchema, input, voice) {\n    const url = ttsSchema?.url || 'https://api.openai.com/v1/audio/speech';\n\n    if (\n      ttsSchema?.voices &&\n      ttsSchema.voices.length > 0 &&\n      !ttsSchema.voices.includes(voice) &&\n      !ttsSchema.voices.includes('ALL')\n    ) {\n      throw new Error(`Voice ${voice} is not available.`);\n    }\n\n    const data = {\n      input,\n      model: ttsSchema?.model,\n      voice: ttsSchema?.voices && ttsSchema.voices.length > 0 ? voice : undefined,\n      backend: ttsSchema?.backend,\n    };\n\n    const apiKey = resolveConfigSecret(ttsSchema?.apiKey) || '';\n    const headers = {\n      'Content-Type': 'application/json',\n      ...(apiKey && { Authorization: `Bearer ${apiKey}` }),\n    };\n\n    return [url, data, headers];\n  }\n","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/Files/Audio/TTSService.js#L101-L137","documentation":"openAIProvider rejects a voice that is not in ttsSchema.voices, unless the list contains the sentinel 'ALL'. The check only runs when `voices` is a non-empty array, so an unset/empty voices list disables the allowlist (any voice passes). A configured list thus acts as a strict gate.","triggerScenarios":"POST /api/speech/tts with the openai provider and a voice id not present in ttsSchema.openai.voices (and the list does not include 'ALL').","commonSituations":"Frontend cached an older voice list; config voices changed; voice id typo; user-supplied voice not in the allowlist.","solutions":["Use a voice id returned by GET /api/voices for the current provider.","Add the desired voice id to ttsSchema.openai.voices in librechat.yaml.","If you want to allow any voice, include 'ALL' in the voices list (or leave voices unset)."],"exampleFix":"# before\nspeech:\n  tts:\n    openai:\n      voices: ['alloy', 'echo']\n# request uses voice='nova' -> error\n\n# after\nspeech:\n  tts:\n    openai:\n      voices: ['alloy', 'echo', 'nova']","handlingStrategy":"validation","validationCode":"const allowed = ttsSchema?.voices;\nif (Array.isArray(allowed) && allowed.length > 0 && !allowed.includes(voice) && !allowed.includes('ALL')) {\n  return res.status(400).json({ error: `Voice ${voice} is not in the allowed list.` });\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch the voice list from GET /api/voices and only offer ids it returns.","Include 'ALL' in voices (or leave voices unset) to disable the allowlist when not needed.","Re-fetch voices after config changes."],"tags":["tts","openai","voice","input-validation"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}