{"record":{"id":"773faf14f8a51601","repo":"SubtitleEdit/subtitleedit","slug":"mistral-voice-list-request-failed-http-int-resu","errorCode":null,"errorMessage":"Mistral voice list request failed: HTTP {(int)result.StatusCode} {result.StatusCode}","messagePattern":"Mistral voice list request failed: HTTP (.+?) (.+?)","errorType":"exception","errorClass":"HttpRequestException","httpStatus":null,"severity":"error","filePath":"src/ui/Logic/Download/TtsDownloadService.cs","lineNumber":776,"sourceCode":"\n    public async Task DownloadMistralSpeechVoiceList(MemoryStream ms, IProgress<float>? progress, CancellationToken cancellationToken)\n    {\n        var url = \"https://api.mistral.ai/v1/audio/voices?limit=10000\";\n\n        using var requestMessage = new HttpRequestMessage(HttpMethod.Get, url);\n        requestMessage.Headers.TryAddWithoutValidation(\"Content-Type\", \"application/json\");\n        requestMessage.Headers.TryAddWithoutValidation(\"Accept\", \"application/json\");\n        requestMessage.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", Se.Settings.Video.TextToSpeech.MistralApiKey);\n\n        var result = await _httpClient.SendAsync(requestMessage, cancellationToken);\n\n        // Throw instead of returning with an empty stream: the caller writes the stream over its\n        // cached voice-list JSON, so a silently failed refresh permanently emptied the voice list\n        // (the bundled fallback only restores when the file is missing).\n        if (!result.IsSuccessStatusCode)\n        {\n            SeLogger.Error($\"Mistral TTS failed calling API address {url} : Status code={result.StatusCode}\");\n            throw new HttpRequestException($\"Mistral voice list request failed: HTTP {(int)result.StatusCode} {result.StatusCode}\");\n        }\n\n        await result.Content.CopyToAsync(ms, cancellationToken);\n    }\n\n    public async Task<bool> DownloadMistralSpeechSpeak(\n        string inputText,\n        MistralVoice voice,\n        string model,\n        string apiKey,\n        MemoryStream stream,\n        IProgress<float>? progress,\n        CancellationToken cancellationToken)\n    {\n        var url = \"https://api.mistral.ai/v1/audio/speech\";\n        var text = Utilities.UnbreakLine(inputText);\n\n        var data = \"{ \\\"model\\\": \\\"\" + Json.EncodeJsonText(model) +","sourceCodeStart":758,"sourceCodeEnd":794,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Logic/Download/TtsDownloadService.cs#L758-L794","documentation":"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.","triggerScenarios":"_httpClient.SendAsync with Bearer MistralApiKey returns !IsSuccessStatusCode. Status logged; status code surfaced in the thrown message.","commonSituations":"Invalid/expired MistralApiKey (401), quota/throttle (429), wrong endpoint, or Mistral-side outage (5xx).","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (string.IsNullOrWhiteSpace(Se.Settings.Video.TextToSpeech.MistralApiKey))\n{\n    throw new InvalidOperationException(\"Mistral API key is not set.\");\n}","typeGuard":null,"tryCatchPattern":"try { await service.DownloadMistralVoiceList(ms, progress, ct); }\ncatch (HttpRequestException ex) when (ex.Message.Contains(\"Mistral voice list\"))\n{\n    // keep cached voice list; show the status code to the user\n}","preventionTips":["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."],"tags":["network","http","tts","mistral","voice-list","csharp"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}