SubtitleEdit/subtitleedit · error · TimeoutException

DashScope transcription timed out after {_settings.TimeoutSe

Error message

DashScope transcription timed out after {_settings.TimeoutSeconds} seconds.

What it means

Thrown when the DashScope speech-to-text pipeline's internal timeout (TimeoutSeconds setting) fires via a linked CancellationTokenSource, distinct from a user-initiated cancel. The catch guard `when (!cancellationToken.IsCancellationRequested)` ensures only the timeout CTS (not user cancel) triggers this TimeoutException. The pipeline includes upload, submit, and polling steps, any of which can exceed the timeout.

Source

Thrown at src/ui/Features/Video/SpeechToText/DashScope/DashScopeSttService.cs:102

            progress?.Report("Submitting transcription task...");
            _settings.Logger?.Invoke($"DashScope: submitting async task for {ossUrl}");
            var taskId = await SubmitTaskAsync(ossUrl, language, ct);

            progress?.Report("Waiting for transcription to complete...");
            var transcriptionUrl = await PollTaskAsync(taskId, ct);

            _settings.Logger?.Invoke($"DashScope: fetching result from {transcriptionUrl}");
            using var resultResponse = await _httpClient.GetAsync(transcriptionUrl, HttpCompletionOption.ResponseHeadersRead, ct);
            resultResponse.EnsureSuccessStatusCode();
            var resultJson = await resultResponse.Content.ReadAsStringAsync(ct);

            return ParseTranscriptionResult(resultJson);
        }
        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($"DashScope transcription timed out after {_settings.TimeoutSeconds} seconds.");
        }
    }

    /// <summary>
    /// Upload the audio to DashScope temporary storage and return its
    /// <c>oss://</c> URL. Two steps: fetch an upload policy, then POST the file
    /// to the returned OSS host with the signed form fields (file field last).
    /// </summary>
    private async Task<string> UploadFileAsync(byte[] audioBytes, string fileName, CancellationToken ct)
    {
        var model = string.IsNullOrWhiteSpace(_settings.Model) ? "qwen3-asr-flash-filetrans" : _settings.Model;
        var policyUrl = $"{BaseUrl}{UploadsPath}?action=getPolicy&model={Uri.EscapeDataString(model)}";
        using var policyRequest = new HttpRequestMessage(HttpMethod.Get, policyUrl);
        policyRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _settings.ApiKey);

        using var policyResponse = await _httpClient.SendAsync(policyRequest, HttpCompletionOption.ResponseHeadersRead, ct);
        if (!policyResponse.IsSuccessStatusCode)
        {

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Increase _settings.TimeoutSeconds to accommodate the audio length (rough rule: 1-2 minutes per 10 minutes of audio for the polling phase).
  2. Set TimeoutSeconds to 0 to disable the internal timeout entirely and rely only on user cancellation.
  3. Pre-split long audio files into shorter segments before submission.
  4. Check DashScope's status page for queue delays if timeouts are intermittent.
  5. Verify network bandwidth is sufficient for the upload step (audio is uploaded in full before processing begins).
Defensive patterns

Strategy: validation

Validate before calling

// Scale the timeout to audio duration before starting
var audioDurationSeconds = GetAudioDuration(audioFilePath);
var minTimeout = (int)(audioDurationSeconds * 0.5) + 120; // 50% of audio + 2 min overhead
if (_settings.TimeoutSeconds > 0 && _settings.TimeoutSeconds < minTimeout)
    _settings = _settings with { TimeoutSeconds = minTimeout };

Try / catch

try { return await service.TranscribeAsync(audioPath, language, progress, segProgress, ct); }
catch (TimeoutException ex) when (ex.Message.Contains("DashScope"))
{ /* increase TimeoutSeconds, re-split audio, or retry */ }

Prevention

When it happens

Trigger: TimeoutSeconds > 0 is set and the linked CTS cancels during UploadFileAsync, SubmitTaskAsync, PollTaskAsync, or the result download — while the user's own cancellationToken has not been cancelled. Common during long audio files where the polling loop (3-second intervals) runs for minutes.

Common situations: Transcribing a long audio file (30+ minutes) with a low TimeoutSeconds setting; DashScope's task queue is slow and polling takes longer than expected; the upload step is slow on a constrained network; TimeoutSeconds was left at a default that's too low for production audio lengths.

Understand the failure class

Related errors


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