SubtitleEdit/subtitleedit · error · HttpRequestException

Murf voice list request failed: HTTP {(int)result.StatusCode

Error message

Murf voice list request failed: HTTP {(int)result.StatusCode} {result.StatusCode}

What it means

HttpRequestException from DownloadMurfVoiceList on a non-2xx response, mirroring the ElevenLabs design. The comment notes an error body must never reach the cached voice list, so the call throws instead of writing an error payload to the cache.

Source

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

    }

    public async Task DownloadMurfVoiceList(MemoryStream ms, IProgress<float>? progress, CancellationToken cancellationToken)
    {
        var url = "https://api.murf.ai/v1/speech/voices";

        using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
        requestMessage.Headers.TryAddWithoutValidation("Content-Type", "application/json");
        requestMessage.Headers.TryAddWithoutValidation("Accept", "application/json");
        requestMessage.Headers.TryAddWithoutValidation("api-key", Se.Settings.Video.TextToSpeech.MurfApiKey);

        var result = await _httpClient.SendAsync(requestMessage, cancellationToken);

        // See DownloadElevenLabsVoiceList: an error body must not reach the cached voice list.
        if (!result.IsSuccessStatusCode)
        {
            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.");
        }

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Confirm MurfApiKey in settings is current and valid.
  2. Check Murf account quota and plan limits.
  3. Read the trimmed error in SeLogger for the server's reason.
  4. Retry on transient 5xx after backoff.
Defensive patterns

Strategy: try-catch

Validate before calling

if (string.IsNullOrWhiteSpace(Se.Settings.Video.TextToSpeech.MurfApiKey))
{
    throw new InvalidOperationException("Murf API key is not set.");
}

Try / catch

try { await service.DownloadMurfVoiceList(ms, progress, ct); }
catch (HttpRequestException ex) when (ex.Message.Contains("Murf voice list"))
{
    // preserve the cached voice list; show the status code to the user
}

Prevention

When it happens

Trigger: GET https://api.murf.ai/v1/speech/voices with the user's MurfApiKey returns !IsSuccessStatusCode. Trimmed body logged, status code in the thrown message.

Common situations: Invalid/expired Murf API key (401), quota hit (429), wrong key in MurfApiKey setting, or a Murr-side outage (5xx).

Related errors


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