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
- Examine the raw policyJson included in the error message to see the actual response structure.
- If the JSON structure changed, update the DashScopeUploadPolicyResponse class to match the new schema.
- If the response is HTML, investigate proxy/CDN interference in the network path.
- Verify the API key has upload/storage permissions in the DashScope console.
- 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
- Check the Content-Type header is application/json before deserialization.
- Log the raw response body for any deserialization failure to aid schema debugging.
- Pin to a known DashScope API version if versioned endpoints are available.
- Monitor DashScope API changelog for response schema updates.
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
- DashScope async submit returned no task_id. Response: {json}
- DashScope task succeeded but returned no transcription_url.
- DashScope transcription timed out after {_settings.TimeoutSe
- 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/c37a6b5b689069f3.
Report an issue: GitHub.