SubtitleEdit/subtitleedit · error · TimeoutException
OpenRouter transcription timed out after {_settings.TimeoutS
Error message
OpenRouter transcription timed out after {_settings.TimeoutSeconds} seconds. What it means
Same timeout pattern as the OpenAI-compatible engine but for OpenRouter: the internal timeoutCTS (CancelAfter TimeoutSeconds) fires before TranscribeCoreAsync returns, and it is not a user cancel. Wrapped as TimeoutException so it is not mistaken for caller cancellation.
Source
Thrown at src/ui/Features/Video/SpeechToText/OpenRouter/OpenRouterSttService.cs:83
string? language,
CancellationToken cancellationToken)
{
using var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
if (_settings.TimeoutSeconds > 0)
{
timeoutCts.CancelAfter(TimeSpan.FromSeconds(_settings.TimeoutSeconds));
}
var ct = timeoutCts.Token;
try
{
return await TranscribeCoreAsync(audioBytes, format, language, ct);
}
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
{
// Our own timeout fired, not a user cancel — surface it as an error
// so the caller doesn't mistake it for cancellation.
throw new TimeoutException($"OpenRouter transcription timed out after {_settings.TimeoutSeconds} seconds.");
}
}
private async Task<OpenAiCompatibleSttResponse> TranscribeCoreAsync(
byte[] audioBytes,
string format,
string? language,
CancellationToken cancellationToken)
{
var body = BuildRequestBody(_settings, audioBytes, format, language);
using var content = new StringContent(body, Encoding.UTF8, "application/json");
using var request = new HttpRequestMessage(HttpMethod.Post, _settings.EndpointUrl)
{
Content = content,
};
if (!string.IsNullOrEmpty(_settings.ApiKey))
{View on GitHub (pinned to 17a9f07487)
Solutions
- Increase _settings.TimeoutSeconds for OpenRouter.
- Pick a faster underlying model in OpenRouter settings.
- Verify network path to OpenRouter.
- Shorten the audio clip per request.
Example fix
// before _settings.TimeoutSeconds = 60; // after: base64-encoded body + remote inference needs more headroom _settings.TimeoutSeconds = 240;
Defensive patterns
Strategy: retry
Validate before calling
if (_settings.TimeoutSeconds < 120) _settings.TimeoutSeconds = 120; // base64 body + remote infer
Try / catch
try { return await openRouter.TranscribeAsync(...); }
catch (TimeoutException ex) when (ex.Message.Contains("OpenRouter transcription timed out"))
{ /* raise TimeoutSeconds or pick a faster model, then retry */ } Prevention
- Account for base64 inflation of the audio body when sizing the timeout.
- Pick a faster underlying OpenRouter model for long clips.
- Retry on timeout only after confirming the caller did not cancel.
When it happens
Trigger: OpenRouter TranscribeCoreAsync (POST _settings.EndpointUrl with base64 audio body) exceeds _settings.TimeoutSeconds while the caller's token is still active.
Common situations: OpenRouter routing to a slow underlying model; large base64 body inflating upload time; TimeoutSeconds too low for the chosen model; network stall.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- DashScope transcription timed out after {_settings.TimeoutSe
- STT request timed out after {_settings.TimeoutSeconds} secon
- OpenRouter STT request failed with status {statusCode} ({res
- DashScope upload-policy request failed ({(int)policyResponse
- DashScope OSS upload failed ({(int)uploadResponse.StatusCode
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/a163354b1ea4c16a.
Report an issue: GitHub.