SubtitleEdit/subtitleedit · error · InvalidOperationException

Azure region is not set - enter it in the TTS engine setting

Error message

Azure region is not set - enter it in the TTS engine settings before refreshing voices.

What it means

InvalidOperationException thrown by DownloadAzureVoiceList before any network call when Se.Settings.Video.TextToSpeech.AzureRegion is blank. Azure's voice-list endpoint is region-specific ({region}.tts.speech.microsoft.com), so without a region the URL cannot even be constructed.

Source

Thrown at src/ui/Logic/Download/TtsDownloadService.cs:268

            var error = (await result.Content.ReadAsStringAsync(cancellationToken)).Trim();
            SeLogger.Error($"Murf TTS failed calling API address {url} : Status code={result.StatusCode} {TruncateForLog(error)}");
            throw new HttpRequestException($"Murf voice list request failed: HTTP {(int)result.StatusCode} {result.StatusCode}");
        }

        await result.Content.CopyToAsync(ms, cancellationToken);
    }

    public async Task DownloadAzureVoiceList(Stream stream, IProgress<float>? progress, CancellationToken cancellationToken)
    {
        // Azure's official voice-list endpoint (the previous URL pointed at the ElevenLabs API,
        // whose response Azure's parser cannot read). Requires the user's region + subscription
        // key; the response is a JSON array with DisplayName/ShortName/Gender/Locale fields -
        // the exact shape AzureSpeech.Map parses. Throws on failure so a refresh cannot
        // overwrite the cached voice list with an error body.
        var region = Se.Settings.Video.TextToSpeech.AzureRegion;
        if (string.IsNullOrWhiteSpace(region))
        {
            throw new InvalidOperationException("Azure region is not set - enter it in the TTS engine settings before refreshing voices.");
        }

        var url = $"https://{region.Trim()}.tts.speech.microsoft.com/cognitiveservices/voices/list";
        using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
        requestMessage.Headers.TryAddWithoutValidation("Ocp-Apim-Subscription-Key", Se.Settings.Video.TextToSpeech.AzureApiKey.Trim());
        var result = await _httpClient.SendAsync(requestMessage, cancellationToken);
        result.EnsureSuccessStatusCode();
        await result.Content.CopyToAsync(stream, cancellationToken);
    }

    public async Task<(bool Ok, string Error)> DownloadElevenLabsVoiceSpeak(
        string inputText,
        ElevenLabVoice voice,
        string model,
        string apiKey,
        string languageCode,
        MemoryStream stream,
        IProgress<float>? progress,

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Open TTS engine settings and enter the Azure region (e.g. eastus, westeurope).
  2. Ensure the region matches the one the subscription key was provisioned in.
  3. Save settings and retry the voice refresh.
  4. If migrating settings, verify AzureRegion survived the migration.
Defensive patterns

Strategy: validation

Validate before calling

var region = Se.Settings.Video.TextToSpeech.AzureRegion;
if (string.IsNullOrWhiteSpace(region))
{
    throw new InvalidOperationException("Set AzureRegion in TTS settings before refreshing voices.");
}

Try / catch

try { await service.DownloadAzureVoiceList(stream, progress, ct); }
catch (InvalidOperationException ex) when (ex.Message.Contains("Azure region is not set"))
{ /* open TTS settings focused on the Azure region field */ }

Prevention

When it happens

Trigger: string.IsNullOrWhiteSpace(region) is true at the top of DownloadAzureVoiceList; the throw happens before the request is built.

Common situations: User added an Azure API key but never set the region, or the settings migration cleared AzureRegion. The message directs the user to the TTS engine settings.

Related errors


AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13). Data as JSON: /api/errors/de8b0545b6a10eb0. Report an issue: GitHub.