{"record":{"id":"113d91a16d3e9613","repo":"SubtitleEdit/subtitleedit","slug":"dashscope-task-succeeded-but-returned-no-transcrip","errorCode":null,"errorMessage":"DashScope task succeeded but returned no transcription_url. Response: {json}","messagePattern":"DashScope task succeeded but returned no transcription_url\\. Response: (.+?)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/ui/Features/Video/SpeechToText/DashScope/DashScopeSttService.cs","lineNumber":220,"sourceCode":"            request.Headers.Authorization = new AuthenticationHeaderValue(\"Bearer\", _settings.ApiKey);\n\n            using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, ct);\n            var json = await response.Content.ReadAsStringAsync(ct);\n            if (!response.IsSuccessStatusCode)\n            {\n                throw new HttpRequestException($\"DashScope task poll failed ({(int)response.StatusCode}). Response: {json}\");\n            }\n\n            var output = JsonSerializer.Deserialize<DashScopeTaskResponse>(json, options)?.Output;\n            var status = output?.TaskStatus ?? \"UNKNOWN\";\n            switch (status.ToUpperInvariant())\n            {\n                case \"SUCCEEDED\":\n                    var transcriptionUrl = output?.Result?.TranscriptionUrl\n                        ?? (output?.Results != null && output.Results.Count > 0 ? output.Results[0].TranscriptionUrl : null);\n                    if (string.IsNullOrEmpty(transcriptionUrl))\n                    {\n                        throw new InvalidOperationException($\"DashScope task succeeded but returned no transcription_url. Response: {json}\");\n                    }\n                    return transcriptionUrl;\n\n                case \"FAILED\":\n                case \"UNKNOWN\":\n                    throw new InvalidOperationException($\"DashScope transcription task {status}. Response: {json}\");\n\n                default: // QUEUED, PENDING, PROCESSING\n                    await Task.Delay(TimeSpan.FromSeconds(3), ct);\n                    break;\n            }\n        }\n    }\n\n    /// <summary>\n    /// Serialize the async submit body. <c>enable_words</c> adds word-level\n    /// timings; a fixed language is sent only when the user set one.\n    /// </summary>","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/SubtitleEdit/subtitleedit/blob/17a9f0748781032255db3526b7215d2fb891e3af/src/ui/Features/Video/SpeechToText/DashScope/DashScopeSttService.cs#L202-L238","documentation":"Thrown when the task status is SUCCEEDED but neither Output.Result.TranscriptionUrl nor Output.Results[0].TranscriptionUrl is present. The transcription completed but DashScope didn't return a URL to download the result JSON, making the output inaccessible.","triggerScenarios":"The response JSON for a SUCCEEDED task lacks the transcription_url field in both Result and Results; the Results array is empty; the field was renamed in a DashScope API update; the result URL was redacted due to OSS expiry.","commonSituations":"DashScope API schema change renamed or moved transcription_url; the task succeeded but the result file expired on OSS before the poll fetched it; the account's OSS retention policy deleted the output; a partial success where transcription ran but URL generation failed server-side.","solutions":["Inspect the raw json in the error to see what fields the SUCCEEDED response actually contains.","If transcription_url moved, update DashScopeTaskResponse's Result/Results DTOs to match the new schema.","Re-run the transcription — if OSS expiry is the cause, the URL will be fresh on a new task.","Check DashScope release notes for API response format changes.","Report to DashScope support if the response genuinely lacks the URL on a confirmed SUCCEEDED task."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Defensive JSON inspection before accessing transcription_url\nusing var doc = JsonDocument.Parse(json);\nvar root = doc.RootElement;\nstring? url = null;\nif (root.TryGetProperty(\"output\", out var outEl))\n{\n    if (outEl.TryGetProperty(\"result\", out var resEl) && resEl.TryGetProperty(\"transcription_url\", out var u1))\n        url = u1.GetString();\n    else if (outEl.TryGetProperty(\"results\", out var resArr) && resArr.GetArrayLength() > 0\n             && resArr[0].TryGetProperty(\"transcription_url\", out var u2))\n        url = u2.GetString();\n}\nif (string.IsNullOrEmpty(url))\n    throw new InvalidOperationException(\"SUCCEEDED task missing transcription_url.\");","typeGuard":null,"tryCatchPattern":"try { return await PollTaskAsync(taskId, ct); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"no transcription_url\"))\n{ /* log JSON, check if URL field moved, re-run transcription if expired */ }","preventionTips":["Log the full JSON response for SUCCEEDED tasks to detect schema changes.","Check both Result.TranscriptionUrl and Results[0].TranscriptionUrl (the code already does this).","Re-run the transcription task if the URL is missing — it may be an OSS expiry issue.","Monitor DashScope API changelog for response format updates."],"tags":["deserialization","dashscope","speech-to-text","schema-mismatch","missing-field"],"backgroundTag":null,"analyzedSha":"17a9f0748781032255db3526b7215d2fb891e3af","analyzedAt":"2026-08-13T18:11:43.374Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}