{"record":{"id":"681a47bdc1c84c9c","repo":"ChatGPTNextWeb/NextChat","slug":"could-not-infer-voicelocale-from-voicename","errorCode":null,"errorMessage":"Could not infer voiceLocale from voiceName!","messagePattern":"Could not infer voiceLocale from voiceName!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/utils/ms_edge_tts.ts","lineNumber":296,"sourceCode":"   * @param voiceName a string with any `ShortName`. A list of all available neural voices can be found [here](https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/language-support#neural-voices). However, it is not limited to neural voices: standard voices can also be used. A list of standard voices can be found [here](https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/language-support#standard-voices)\n   * @param outputFormat any {@link OUTPUT_FORMAT}\n   * @param voiceLocale (optional) any voice locale that is supported by the voice. See the list of all voices for compatibility. If not provided, the locale will be inferred from the `voiceName`\n   */\n  async setMetadata(\n    voiceName: string,\n    outputFormat: OUTPUT_FORMAT,\n    voiceLocale?: string,\n  ) {\n    const oldVoice = this._voice;\n    const oldVoiceLocale = this._voiceLocale;\n    const oldOutputFormat = this._outputFormat;\n\n    this._voice = voiceName;\n    this._voiceLocale = voiceLocale;\n    if (!this._voiceLocale) {\n      const voiceLangMatch = MsEdgeTTS.VOICE_LANG_REGEX.exec(this._voice);\n      if (!voiceLangMatch)\n        throw new Error(\"Could not infer voiceLocale from voiceName!\");\n      this._voiceLocale = voiceLangMatch[0];\n    }\n    this._outputFormat = outputFormat;\n\n    const changed =\n      oldVoice !== this._voice ||\n      oldVoiceLocale !== this._voiceLocale ||\n      oldOutputFormat !== this._outputFormat;\n\n    // create new client\n    if (changed || this._ws!.readyState !== this._ws!.OPEN) {\n      this._startTime = Date.now();\n      await this._initClient();\n    }\n  }\n\n  private _metadataCheck() {\n    if (!this._ws)","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/ChatGPTNextWeb/NextChat/blob/defdcdb55d850cd12c4c657eb83729fd66e215c0/app/utils/ms_edge_tts.ts#L278-L314","documentation":"Thrown at app/utils/ms_edge_tts.ts:296 inside setMetadata when voiceLocale is not supplied and the voiceName fails to match VOICE_LANG_REGEX (=/\\w{2}-\\w{2}/). The regex extracts a locale like 'en-US' from a ShortName voice such as 'en-US-AriaNeural'; if the voiceName lacks that 'XX-XX' locale segment, inference fails and synthesis cannot proceed because the SSML xml:lang would be empty.","triggerScenarios":"Passing a voiceName with no locale segment (e.g. 'Aria', 'MyCustomVoice', or a malformed/empty string); passing a voiceName with an uppercase country-only or language-only segment that does not match the two-letter-two-letter pattern; passing a LongName or multilingual voice id whose format differs from ShortName.","commonSituations":"Hard-coding a voice display name instead of its ShortName; user types a custom voice string in settings; voice list loaded from a different/older source whose names don't include the locale; passing undefined/'' accidentally.","solutions":["Always pass an official ShortName (e.g. 'en-US-AriaNeural') obtained from getVoices().","Pass an explicit voiceLocale argument to setMetadata so inference is not relied upon.","Validate voiceName against /\\w{2}-\\w{2}/ before calling setMetadata and warn the user early.","If supporting non-ShortName voices, build a voiceName->locale lookup from the voices list and look it up instead of regex inference."],"exampleFix":"// before\nawait tts.setMetadata('Aria', OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3);\n\n// after\nconst voiceName = 'en-US-AriaNeural';\nawait tts.setMetadata(\n  voiceName,\n  OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3,\n  'en-US', // explicit locale, no inference needed\n);","handlingStrategy":"validation","validationCode":"const VOICE_LOCALE_RE = /\\w{2}-\\w{2}/;\n\nfunction canInferLocale(voiceName: string): boolean {\n  return VOICE_LOCALE_RE.test(voiceName);\n}\n\nif (!canInferLocale(voiceName)) {\n  throw new Error(\n    `voiceName \"${voiceName}\" has no locale segment; pass an explicit voiceLocale`,\n  );\n}\nawait tts.setMetadata(voiceName, outputFormat);","typeGuard":"function isShortNameVoice(name: string): boolean {\n  // ShortName format: <locale>-<VoiceName>Neural, e.g. en-US-AriaNeural\n  return /^\\w{2}-\\w{2}-\\w+Neural$/.test(name);\n}","tryCatchPattern":"try {\n  await tts.setMetadata(voiceName, outputFormat);\n} catch (e) {\n  if (e instanceof Error && /infer voiceLocale/.test(e.message)) {\n    await tts.setMetadata(voiceName, outputFormat, \"en-US\"); // explicit fallback locale\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always source voiceName from getVoices() output rather than hard-coding it.","Pass an explicit voiceLocale to setMetadata to skip regex inference entirely.","Validate the ShortName format before offering it as a selectable voice."],"tags":["edge-tts","validation","voice","regex","ssml"],"backgroundTag":null,"analyzedSha":"defdcdb55d850cd12c4c657eb83729fd66e215c0","analyzedAt":"2026-08-12T09:57:26.489Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}