yikart/AiToEarn · error · Error
上传确认失败
Error message
上传确认失败
What it means
thrown by confirmUpload after a client-side direct OSS/S3 upload, when the confirm API response is missing or its code !== 0 (the app's success code). The backend uses this call to mark the asset uploaded and return its final URL; failure means the object may exist in storage but is not registered, so the function throws '上传确认失败' unless the server supplied a message.
Source
Thrown at project/aitoearn-web/src/api/materials/material.api.ts:94
})
if (!res || res.code !== 0)
throw new Error(res?.message || '获取上传签名失败')
return res.data
}
async function confirmUpload(assetId: string, fallbackUrl: string, publicUploadId?: string) {
const confirmResponse = await request<ConfirmUploadData>({
url: getConfirmRequestPath(assetId, publicUploadId),
method: 'POST',
data: {
id: assetId,
},
})
if (!confirmResponse || confirmResponse.code !== 0)
throw new Error(confirmResponse?.message || '上传确认失败')
return confirmResponse.data?.url || fallbackUrl
}
/**
* 上传文件到OSS (前端直传 AWS S3)
*/
export async function uploadToOss(
file: File | Blob,
options?: UploadToOssOptions | ((prog: number) => void),
): Promise<string> {
try {
const opts: UploadToOssOptions
= typeof options === 'function' ? { onProgress: options } : (options ?? {})
if (opts.signal?.aborted) {
throw new DOMException('上传已取消', 'AbortError')
}View on GitHub (pinned to d3aa8bea5b)
Solutions
- Inspect confirmResponse.code/message for the server-side reason.
- Re-authenticate and retry confirmUpload alone — the file is already in OSS, no need to re-upload.
- Verify assetId comes from the presignedData response unchanged.
- Check backend logs for the confirm endpoint failure (DB/asset-not-found).
Example fix
// before
if (!confirmResponse || confirmResponse.code !== 0)
throw new Error(confirmResponse?.message || '上传确认失败')
// after
if (!confirmResponse || confirmResponse.code !== 0)
throw new Error(`上传确认失败: ${confirmResponse?.message ?? 'no response'} (assetId=${assetId})`) Defensive patterns
Strategy: retry
Validate before calling
// confirm only after a verified successful PUT
if (!uploadResponse.ok) throw new Error('上传未完成,跳过确认')
// then call confirmUpload(assetId, fallbackUrl) Type guard
function isConfirmResult(r: unknown): r is { code: number; message?: string; data?: { url?: string } } {
const o = r as any
return !!o && typeof o.code === 'number'
} Try / catch
try {
const url = await confirmUpload(assetId, fallbackUrl)
}
catch (e) {
// file already in OSS — safe to retry confirm alone
await sleep(1000)
const url = await confirmUpload(assetId, fallbackUrl)
} Prevention
- Make confirmUpload idempotent so it can be retried safely after the PUT succeeded.
- Persist assetId + fallbackUrl so confirm can be retried after page reloads.
- Refresh auth tokens before long uploads complete to avoid expired-session confirms.
- Alert on confirm-endpoint 5xx; separate presign/PUT/confirm failures in monitoring.
When it happens
Trigger: uploadToOss completes the PUT to the presigned URL and then calls confirmUpload, but the confirm endpoint fails: expired session, assetId not found, backend DB error, or the request layer returned undefined (network error).
Common situations: Long uploads outliving the auth token; confirm endpoint 5xx under load; assetId mismatch after the presign response shape changed; double-submit races deleting the asset record.
Related errors
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/0371202eb8715c64.
Report an issue: GitHub.