SubtitleEdit/subtitleedit · error · HttpRequestException

DashScope upload-policy request failed ({(int)policyResponse

Error message

DashScope upload-policy request failed ({(int)policyResponse.StatusCode}). Response: {err}

What it means

Thrown when the GET request to DashScope's upload-policy endpoint (/api/v1/uploads?action=getPolicy&model=...) returns a non-success HTTP status code. The policy is the first step of the pipeline — without it, the OSS upload cannot proceed. The status code and full response body are included in the message and logged.

Source

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

    /// <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)
        {
            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" },

View on GitHub (pinned to 17a9f07487)

Solutions

  1. Check the HTTP status code in the error: 401/403 means the API key is wrong or expired — regenerate and re-enter it.
  2. Verify the region setting matches the API key's account region (china vs international base URL).
  3. Confirm the ASR model is enabled and available in the DashScope console for your account.
  4. Test the API key with a simple curl: curl -H 'Authorization: Bearer <key>' '<policyUrl>'.
  5. If 5xx, retry after a short delay — DashScope may be experiencing a transient outage.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate API key and region before the pipeline starts
if (string.IsNullOrWhiteSpace(_settings.ApiKey))
    throw new InvalidOperationException("DashScope API key is not set.");
var expectedBaseUrl = DashScopeSttService.GetBaseUrl(_settings.Region);
if (_settings.Region != "china" && !expectedBaseUrl.Contains("intl"))
    throw new InvalidOperationException($"Region '{_settings.Region}' may not match the API key's account region.");

Try / catch

try { var policy = await GetUploadPolicy(ct); }
catch (HttpRequestException ex) when (ex.Message.Contains("upload-policy request failed"))
{
    var code = ExtractStatusCode(ex.Message);
    if (code == 401 || code == 403) /* re-prompt for API key */;
    else if (code >= 500) /* retry with backoff */;
}

Prevention

When it happens

Trigger: The Bearer token (_settings.ApiKey) is missing, expired, or invalid (expect 401/403); the model name is wrong or not enabled for the account (expect 400); the DashScope API endpoint is unreachable or returns 5xx; the region setting (china vs international) is wrong, hitting the wrong base URL.

Common situations: API key was regenerated on the DashScope console but not updated in settings; using the international base URL with a China-only key or vice versa; the model name 'qwen3-asr-flash-filetrans' is not yet available in the selected region; account has insufficient quota or the ASR service is not activated; network firewall blocks the DashScope API host.

Related errors


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