yikart/AiToEarn · warning · DOMException
上传已取消
Error message
上传已取消
What it means
DOMException with name 'AbortError' thrown at the start of uploadToOss when opts.signal.aborted is already true — i.e. the caller's AbortController was aborted before the upload began. It is the cancel-signal fast path so an aborted upload never starts network work.
Source
Thrown at project/aitoearn-web/src/api/materials/material.api.ts:111
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')
}
const uploadFile = await optimizeImageForUpload(file, { signal: opts.signal })
const fileName = getUploadFileName(uploadFile, opts.publicUploadId)
const fileSize = uploadFile.size
const contentType = uploadFile.type || 'application/octet-stream'
// 获取 presigned post 数据
const presignedData = await getPresignedPostData(fileName, fileSize, contentType, opts.publicUploadId)
// R2 使用 PUT 请求直接上传到 uploadUrl,不需要 FormData
const uploadUrl = presignedData.uploadUrl
// 直传文件到 AWS S3 (支持进度回调)
if (opts.onProgress) {
return new Promise<string>((resolve, reject) => {View on GitHub (pinned to d3aa8bea5b)
Solutions
- Treat DOMException with name === 'AbortError' as an expected cancellation, not a failure — skip error toasts/logging.
- Create a fresh AbortController per upload attempt.
- If cancellation was unintentional (e.g. premature unmount), fix the effect cleanup so the controller isn't aborted too early.
- Check that the cancel UI only aborts the upload it owns.
Example fix
// before
try { await uploadToOss(file, { signal }) } catch (e) { showError(e) }
// after
try {
await uploadToOss(file, { signal })
}
catch (e) {
if (e instanceof DOMException && e.name === 'AbortError') return // cancelled
showError(e)
} Defensive patterns
Strategy: try-catch
Validate before calling
// before starting an upload if (controller.signal.aborted) return // skip entirely; don't even call uploadToOss
Type guard
function isAbortError(e: unknown): e is DOMException {
return e instanceof DOMException && e.name === 'AbortError'
} Try / catch
try {
await uploadToOss(file, { signal: controller.signal })
}
catch (e) {
if (isAbortError(e)) return // expected cancellation
throw e
} Prevention
- Create a new AbortController per upload attempt; never reuse aborted ones.
- Filter AbortError from global error reporting/toasts — it is user-initiated.
- In React effects, only abort uploads owned by that effect instance.
- Debounce rapid unmount/remount cycles (strict mode) to avoid premature aborts.
When it happens
Trigger: The user/UI cancels an upload (abort() on the AbortController) before or as uploadToOss is invoked; a component unmount aborts the controller while the promise is being created; the same signal reused after a previous upload was cancelled.
Common situations: Users closing a modal/leaving a page mid-upload; React strict-mode double effects aborting the first attempt; reusing one AbortController across sequential uploads without resetting it.
Related errors
- 上传已取消
- Upload canceled
- VideoUploadVidNotFound
- Relay uploadSign returned no uploadUrl: ${JSON.stringify(sig
- ChannelPlatformResponseInvalid
AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31).
Data as JSON: /api/errors/d964c82b1b792914.
Report an issue: GitHub.