SubtitleEdit/subtitleedit · error · HttpRequestException
DashScope OSS upload failed
Error message
DashScope OSS upload failed ({(int)uploadResponse.StatusCode}). Response: {err} What it means
Thrown when the multipart form POST to the OSS UploadHost (Alibaba Object Storage) returns a non-success HTTP status. This is the second step: after getting the upload policy, the audio bytes are POSTed directly to OSS using the signed form fields. The status code and OSS error response are included.
Solutions
- Check the OSS status code: 403 means signature/policy mismatch (often clock skew — sync system time); 413 means file too large.
- Ensure the system clock is accurate (NTP sync) — OSS signatures are time-sensitive.
- If the file is large, verify the policy doesn't impose a size limit below the file size.
- Retry the entire flow (getPolicy + upload) if the error is transient (5xx from OSS).
- Inspect the err body in the message for OSS-specific error codes (e.g. InvalidAccessKeyId, SignatureDoesNotMatch).
Defensive patterns
Strategy: retry
Validate before calling
// Ensure system clock is synced before upload (clock skew invalidates OSS signatures)
var ntpOffset = GetNtpOffset();
if (Math.Abs(ntpOffset.TotalSeconds) > 30)
throw new InvalidOperationException("System clock is off by more than 30 seconds; OSS signatures will be rejected."); Try / catch
try { await UploadToOss(policy, audioBytes, ct); }
catch (HttpRequestException ex) when (ex.Message.Contains("OSS upload failed"))
{
var code = ExtractStatusCode(ex.Message);
if (code == 403) /* re-fetch policy (clock skew / expiry), retry */;
else if (code >= 500) /* transient OSS error, retry with backoff */;
} Prevention
- Ensure the system clock is NTP-synced — OSS signed policies are time-sensitive.
- Minimize the time between getPolicy and the OSS POST to avoid policy expiry.
- Verify audio file size is within the policy's content-length limit.
- Implement retry logic for transient OSS 5xx errors.
When it happens
Trigger: The signed policy/expiry has lapsed between getPolicy and the POST (clock skew); the file content exceeds the policy's size limit; the OSS bucket ACL or signature is invalid; the OSS host rejects the multipart encoding; the upload dir in the policy is wrong.
Common situations: Clock skew between client and OSS server causes the signed policy to be expired on arrival; large audio files exceed the policy's content-length limit; the API key's associated OSS bucket is misconfigured; transient OSS errors during peak load.
Related errors
- DashScope async submit failed
- DashScope task poll failed
- DashScope upload-policy request failed
- DashScope transcription timed out after
- OpenRouter STT request failed with status
AI-assisted analysis of SubtitleEdit/subtitleedit@17a9f07487 (2026-08-13).
Data as JSON: /api/errors/52a92a235f884622.
Report an issue: GitHub.
Appendix: source
Thrown at src/ui/Features/Video/SpeechToText/DashScope/DashScopeSttService.cs:156
{
{ 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
using var uploadResponse = await _httpClient.PostAsync(policy.UploadHost, form, ct);
if (!uploadResponse.IsSuccessStatusCode)
{
var err = await uploadResponse.Content.ReadAsStringAsync(ct);
_settings.Logger?.Invoke($"DashScope OSS upload failed: POST {policy.UploadHost} => {(int)uploadResponse.StatusCode}: {err}");
throw new HttpRequestException($"DashScope OSS upload failed ({(int)uploadResponse.StatusCode}). Response: {err}");
}
return "oss://" + key;
}
private async Task<string> SubmitTaskAsync(string ossUrl, string? language, CancellationToken ct)
{
var body = BuildSubmitBody(_settings, ossUrl, language);
using var content = new StringContent(body, Encoding.UTF8, "application/json");
using var request = new HttpRequestMessage(HttpMethod.Post, BaseUrl + TranscriptionPath)
{
Content = content,
};
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _settings.ApiKey);
request.Headers.TryAddWithoutValidation("X-DashScope-Async", "enable");
request.Headers.TryAddWithoutValidation("X-DashScope-OssResourceResolve", "enable");
using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, ct);View on GitHub (pinned to 17a9f07487)