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
- Confirm MurfApiKey in settings is current and valid.
- Check Murf account quota and plan limits.
- Read the trimmed error in SeLogger for the server's reason.
- 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
- Never write an error body into the cached voice-list file (the throw enforces this).
- Confirm MurfApiKey validity and plan quota before refresh.
- Retry transient 5xx with bounded backoff.
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
- ElevenLabs voice list request failed: HTTP {(int)result.Stat
- Mistral voice list request failed: HTTP {(int)result.StatusC
- MOSS-TTS (CrispASR) request failed — the connection to the c
- OmniVoice (CrispASR) request failed — the connection to the
- AllTalk TTS server is not reachable. Please check that the s
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/87d5283aabaf858b.
Report an issue: GitHub.