SubtitleEdit/subtitleedit · error · InvalidOperationException

DashScope upload-policy response could not be parsed. Respon

Error message

DashScope upload-policy response could not be parsed. Response: {policyJson}

What it means

Thrown when the upload-policy endpoint returns HTTP 200 but the JSON body cannot be deserialized into a DashScopeUploadPolicyResponse with a non-null Data property. This means the API changed its response schema, returned an unexpected envelope, or sent HTML instead of JSON (e.g. a CDN error page).

Source

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

        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)
        {
            var err = await policyResponse.Content.ReadAsStringAsync(ct);
            _settings.Logger?.Invoke($"DashScope upload-policy request failed: GET {policyUrl} => {(int)policyResponse.StatusCode}: {err}");
            throw new HttpRequestException($"DashScope upload-policy request failed ({(int)policyResponse.StatusCode}). Response: {err}");
        }

        var policyJson = await policyResponse.Content.ReadAsStringAsync(ct);
        var policy = JsonSerializer.Deserialize<DashScopeUploadPolicyResponse>(policyJson,
            new JsonSerializerOptions { PropertyNameCaseInsensitive = true })?.Data;
        if (policy == null)
        {
            _settings.Logger?.Invoke($"DashScope upload-policy response could not be parsed: {policyJson}");
            throw new InvalidOperationException($"DashScope upload-policy response could not be parsed. Response: {policyJson}");
        }

        var key = $"{policy.UploadDir}/{fileName}";

        using var form = new MultipartFormDataContent
        {
            { new StringContent(policy.OssAccessKeyId), "OSSAccessKeyId" },
            { new StringContent(policy.Policy), "policy" },
            { new StringContent(policy.Signature), "Signature" },
            { new StringContent(key), "key" },
            { new StringContent(policy.XOssObjectAcl), "x-oss-object-acl" },
            { new StringContent(policy.XOssForbidOverwrite), "x-oss-forbid-overwrite" },
            { new StringContent("200"), "success_action_status" },
        };
        var fileContent = new ByteArrayContent(audioBytes);
        fileContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
        form.Add(fileContent, "file", fileName); // file field must be last

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Examine the raw policyJson included in the error message to see the actual response structure.
  2. If the JSON structure changed, update the DashScopeUploadPolicyResponse class to match the new schema.
  3. If the response is HTML, investigate proxy/CDN interference in the network path.
  4. Verify the API key has upload/storage permissions in the DashScope console.
  5. Check if PropertyNameCaseInsensitive is handling the property names correctly — compare the JSON keys against the C# property names.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-validate response is JSON before deserializing
var contentType = policyResponse.Content.Headers.ContentType?.MediaType;
if (contentType != "application/json")
    throw new InvalidOperationException($"Expected JSON from upload-policy endpoint, got {contentType}.");

Try / catch

try { var policy = JsonSerializer.Deserialize<DashScopeUploadPolicyResponse>(policyJson, opts)?.Data; }
catch (JsonException ex)
{ /* log raw JSON, check for schema change, surface actionable error */ }

Prevention

When it happens

Trigger: The response body is valid JSON but the structure doesn't match DashScopeUploadPolicyResponse (e.g. Data is nested differently or uses different property names); the response is not JSON at all (HTML error page with 200 status from a proxy); the response is a JSON error object without a Data field.

Common situations: DashScope updated their API response schema without notice; a transparent proxy or CDN returns a 200 HTML page; the API key is valid but the account lacks upload permissions, returning a JSON error without Data; network middleware rewrites the response body.

Related errors


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