SubtitleEdit/subtitleedit · error · HttpRequestException
Mistral voice list request failed: HTTP {(int)result.StatusC
Error message
Mistral voice list request failed: HTTP {(int)result.StatusCode} {result.StatusCode} What it means
HttpRequestException from DownloadMistralVoiceList on a non-2xx response. Per the comment, throwing (rather than returning an empty stream) prevents a silently failed refresh from permanently emptying the cached voice list, since the bundled fallback only restores when the file is missing.
Source
Thrown at src/ui/Logic/Download/TtsDownloadService.cs:776
public async Task DownloadMistralSpeechVoiceList(MemoryStream ms, IProgress<float>? progress, CancellationToken cancellationToken)
{
var url = "https://api.mistral.ai/v1/audio/voices?limit=10000";
using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
requestMessage.Headers.TryAddWithoutValidation("Content-Type", "application/json");
requestMessage.Headers.TryAddWithoutValidation("Accept", "application/json");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Se.Settings.Video.TextToSpeech.MistralApiKey);
var result = await _httpClient.SendAsync(requestMessage, cancellationToken);
// Throw instead of returning with an empty stream: the caller writes the stream over its
// cached voice-list JSON, so a silently failed refresh permanently emptied the voice list
// (the bundled fallback only restores when the file is missing).
if (!result.IsSuccessStatusCode)
{
SeLogger.Error($"Mistral TTS failed calling API address {url} : Status code={result.StatusCode}");
throw new HttpRequestException($"Mistral voice list request failed: HTTP {(int)result.StatusCode} {result.StatusCode}");
}
await result.Content.CopyToAsync(ms, cancellationToken);
}
public async Task<bool> DownloadMistralSpeechSpeak(
string inputText,
MistralVoice voice,
string model,
string apiKey,
MemoryStream stream,
IProgress<float>? progress,
CancellationToken cancellationToken)
{
var url = "https://api.mistral.ai/v1/audio/speech";
var text = Utilities.UnbreakLine(inputText);
var data = "{ \"model\": \"" + Json.EncodeJsonText(model) +View on GitHub (pinned to 17a9f07487)
Solutions
- Verify MistralApiKey is valid and not expired.
- Check Mistral quota/plan limits (429).
- Inspect the SeLogger status line for the server reason.
- Retry transient 5xx after backoff.
Defensive patterns
Strategy: try-catch
Validate before calling
if (string.IsNullOrWhiteSpace(Se.Settings.Video.TextToSpeech.MistralApiKey))
{
throw new InvalidOperationException("Mistral API key is not set.");
} Try / catch
try { await service.DownloadMistralVoiceList(ms, progress, ct); }
catch (HttpRequestException ex) when (ex.Message.Contains("Mistral voice list"))
{
// keep cached voice list; show the status code to the user
} Prevention
- Do not let a failed refresh empty the cached voice list (the throw enforces this).
- Verify MistralApiKey validity and quota before refresh.
- Retry transient 5xx with bounded backoff.
When it happens
Trigger: _httpClient.SendAsync with Bearer MistralApiKey returns !IsSuccessStatusCode. Status logged; status code surfaced in the thrown message.
Common situations: Invalid/expired MistralApiKey (401), quota/throttle (429), wrong endpoint, or Mistral-side outage (5xx).
Related errors
- ElevenLabs voice list request failed: HTTP {(int)result.Stat
- Murf voice list request failed: HTTP {(int)result.StatusCode
- 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/773faf14f8a51601.
Report an issue: GitHub.