{"record":{"id":"732f33f9cc5ae3a6","repo":"SubtitleEdit/subtitleedit","slug":"stt-request-failed-with-status-statuscode-resp","errorCode":null,"errorMessage":"STT request failed with status {statusCode} ({response.StatusCode}) calling {safeEndpoint}. Response: {errorContent}","messagePattern":"STT request failed with status (.+?) \\((.+?)\\) calling (.+?)\\. Response: (.+?)","errorType":"http","errorClass":"HttpRequestException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/SpeechToText/OpenAiCompatible/OpenAiSttService.cs","lineNumber":229,"sourceCode":"                ? _settings.Temperature.ToString(\"F2\", CultureInfo.InvariantCulture)\n                : \"(not sent)\";\n            var granularitiesSummary = _settings.Stream ? \"(not sent)\" : \"[segment,word]\";\n            var paramSummary =\n                $\"model={_settings.Model}, language={languageToUse}, \" +\n                $\"response_format={responseFormat}, timestamp_granularities={granularitiesSummary}, \" +\n                $\"stream={(_settings.Stream ? \"true\" : \"(not sent)\")}, \" +\n                $\"temperature={temperatureSummary}, \" +\n                $\"promptLen={_settings.Prompt?.Length ?? 0}, file={fileName}\";\n            var safeEndpoint = SanitizeEndpointForLog(_settings.EndpointUrl);\n            _settings.Logger?.Invoke(\n                $\"OpenAI-compatible STT failed: POST {safeEndpoint}{Environment.NewLine}\" +\n                $\"Status: {statusCode} {response.StatusCode}{Environment.NewLine}\" +\n                $\"RequestParams: {paramSummary}{Environment.NewLine}\" +\n                $\"ResponseBody: {errorContent}\");\n            // Carry the status code on the exception: the caller turns a 4xx that\n            // complains about \"model\" into a hint about the Model field, and\n            // sniffing the number back out of the message is fragile (issue #12877).\n            throw new HttpRequestException(\n                $\"STT request failed with status {statusCode} ({response.StatusCode}) \" +\n                $\"calling {safeEndpoint}. Response: {errorContent}\",\n                null,\n                response.StatusCode);\n        }\n\n        // Check if streaming (SSE)\n        var contentType = response.Content.Headers.ContentType?.MediaType ?? \"\";\n        if (contentType.Contains(\"text/event-stream\") || response.Headers.Contains(\"Server-Sent-Events\"))\n        {\n            return await ParseSseStreamAsync(response, progress, segmentProgress, cancellationToken);\n        }\n\n        // Non-streaming response\n        var jsonResponse = await response.Content.ReadAsStringAsync(cancellationToken);\n        return ParseJsonResponse(jsonResponse);\n    }\n","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/SpeechToText/OpenAiCompatible/OpenAiSttService.cs#L211-L247","documentation":"The OpenAI-compatible STT endpoint returned a non-2xx status. The status code is carried on the HttpRequestException (via response.StatusCode) so callers can branch on it — notably a 4xx complaining about 'model' is turned into a Model-field hint (issue #12877). The endpoint is sanitized for logging via SanitizeEndpointForLog before being written to the message or tools log.","triggerScenarios":"Any non-success HTTP status from POST {EndpointUrl}: 400/404 about model name, 401 bad API key, 403 forbidden, 404 wrong endpoint path, 429 rate limit, 5xx server error.","commonSituations":"EndpointUrl points at /v1/chat/completions instead of /v1/audio/transcriptions; wrong or non-existent Model name; expired/invalid API key; rate-limited account; provider outage.","solutions":["Read statusCode and errorContent in the message — a 4xx mentioning 'model' usually means the Model field is wrong (issue #12877).","Confirm EndpointUrl is the STT transcription endpoint, not the chat endpoint.","Validate/rotate the API key.","Back off and retry on 429 rate limits."],"exampleFix":"// before: chat endpoint used for STT\nEndpointUrl = \"https://api.example.com/v1/chat/completions\";\n// after: correct transcription endpoint\nEndpointUrl = \"https://api.example.com/v1/audio/transcriptions\";","handlingStrategy":"try-catch","validationCode":"if (!Uri.TryCreate(_settings.EndpointUrl, UriKind.Absolute, out var uri)\n    || !uri.AbsolutePath.EndsWith(\"/transcriptions\", StringComparison.OrdinalIgnoreCase))\n    return Invalid(\"EndpointUrl must be the /v1/audio/transcriptions URL\");","typeGuard":null,"tryCatchPattern":"try { return await service.TranscribeAsync(...); }\ncatch (HttpRequestException ex) when (ex.StatusCode is HttpStatusCode.BadRequest && ex.Message.Contains(\"model\"))\n{ /* hint: Model field is wrong (issue #12877) */ }\ncatch (HttpRequestException ex) when (ex.StatusCode is HttpStatusCode.Unauthorized)\n{ /* API key invalid */ }","preventionTips":["Point EndpointUrl at the transcription endpoint, never chat/completions.","Keep the status code on the exception so callers can branch (as this engine does).","Sanitize endpoints in logs to avoid leaking keys in URLs."],"tags":["openai-stt","http","network","speech-to-text"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}