SubtitleEdit/subtitleedit · error · HttpRequestException

OpenRouter STT request failed with status {statusCode} ({res

Error message

OpenRouter STT request failed with status {statusCode} ({response.StatusCode}). Response: {errorContent}

What it means

OpenRouter STT endpoint returned non-2xx; the status code and response body are embedded in the message. Note the log line writes _settings.EndpointUrl RAW (unlike the OpenAI path which sanitizes), and the thrown message itself does not include the endpoint.

Source

Thrown at src/ui/Features/Video/SpeechToText/OpenRouter/OpenRouterSttService.cs:119

        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _settings.ApiKey);
        }

        // OpenRouter uses these to attribute traffic; harmless if the server ignores them.
        request.Headers.TryAddWithoutValidation("HTTP-Referer", "https://www.nikse.dk/subtitleedit");
        request.Headers.TryAddWithoutValidation("X-Title", "Subtitle Edit");

        using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
        if (!response.IsSuccessStatusCode)
        {
            var errorContent = await response.Content.ReadAsStringAsync(cancellationToken);
            var statusCode = (int)response.StatusCode;
            _settings.Logger?.Invoke(
                $"OpenRouter STT failed: POST {_settings.EndpointUrl}{Environment.NewLine}" +
                $"Status: {statusCode} {response.StatusCode}{Environment.NewLine}" +
                $"RequestParams: model={_settings.Model}, language={language ?? _settings.Language}, format={format}, bytes={audioBytes.Length}{Environment.NewLine}" +
                $"ResponseBody: {errorContent}");
            throw new HttpRequestException(
                $"OpenRouter STT request failed with status {statusCode} ({response.StatusCode}). Response: {errorContent}");
        }

        var json = await response.Content.ReadAsStringAsync(cancellationToken);
        return ParseResponse(json);
    }

    /// <summary>
    /// Serialize the OpenRouter transcription request body. The audio is
    /// base64-encoded (raw, not a data URI) under <c>input_audio</c>, and
    /// <c>verbose_json</c> + <c>timestamp_granularities[]</c> ask for segment and
    /// word timings when the underlying model supports them.
    /// </summary>
    internal static string BuildRequestBody(OpenRouterSttSettings settings, byte[] audioBytes, string format, string? language)
    {
        using var stream = new MemoryStream();
        using (var writer = new Utf8JsonWriter(stream))
        {

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Read statusCode and errorContent in the message to see the upstream reason.
  2. Confirm _settings.Model is a valid OpenRouter model id that supports audio.
  3. Validate/rotate the API key.
  4. Retry with backoff on 429.

Example fix

// before: model id OpenRouter rejects
Model = "whisper-1";
// after: a model id OpenRouter actually routes for audio
Model = "openai/whisper-large-v3";
Defensive patterns

Strategy: try-catch

Validate before calling

if (string.IsNullOrWhiteSpace(_settings.Model) || !_settings.Model.Contains('/'))
    return Invalid("OpenRouter Model must be a provider/model id");

Try / catch

try { return await openRouter.TranscribeAsync(...); }
catch (HttpRequestException ex) when (ex.Message.Contains("OpenRouter STT request failed"))
{ /* parse statusCode from message; 401 -> key, 404 -> model/endpoint, 429 -> backoff */ }

Prevention

When it happens

Trigger: Non-success status from POST _settings.EndpointUrl: 400 bad model/format, 401 bad API key, 404 wrong endpoint, 429 rate limit, 5xx from OpenRouter or the routed upstream model.

Common situations: Wrong _settings.Model name; invalid/expired OpenRouter API key; endpoint URL misconfigured; rate limit on the account; the routed upstream provider returned an error OpenRouter forwards.

Related errors


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