{"record":{"id":"ddb51a0881137e95","repo":"yikart/AiToEarn","slug":"upload-canceled","errorCode":null,"errorMessage":"Upload canceled","messagePattern":"Upload canceled","errorType":"exception","errorClass":"DOMException","httpStatus":null,"severity":"info","filePath":"project/aitoearn-web/src/components/PublishDialog/compoents/PublishManageUpload/usePublishManageUpload.ts","lineNumber":196,"sourceCode":"            fileName: name,\n            size: file.size ?? 0,\n            type,\n            status: UploadTaskStatusEnum.Hashing,\n            progress: 0,\n            createdAt: Date.now(),\n            updatedAt: Date.now(),\n          },\n        },\n      }))\n\n      const promise = (async (): Promise<UploadResult> => {\n        let currentMd5: string | undefined\n        try {\n          const md5 = computeFileFingerprint(file, name)\n          currentMd5 = md5\n\n          if (canceledTasks.has(taskId)) {\n            throw new DOMException('Upload canceled', 'AbortError')\n          }\n\n          taskMd5Map.set(taskId, md5)\n\n          finalizeTask(taskId, {\n            md5,\n            status: UploadTaskStatusEnum.Pending,\n          })\n\n          const cache = get().md5Cache[md5]\n          if (cache) {\n            const result: UploadResult = { ...cache, fromCache: true }\n            finalizeTask(taskId, {\n              status: UploadTaskStatusEnum.Success,\n              progress: 100,\n              fromCache: true,\n            })\n            return result","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-web/src/components/PublishDialog/compoents/PublishManageUpload/usePublishManageUpload.ts#L178-L214","documentation":"enqueueUpload throws an AbortError DOMException named 'Upload canceled' when the user cancels a task between fingerprint computation (computeFileFingerprint) and registering the task's md5. The queue keeps a canceledTasks set keyed by taskId; at each async checkpoint it re-checks membership and aborts so a canceled file never proceeds to upload. This is a normal, user-initiated control-flow signal, not a fault.","triggerScenarios":"Calling enqueueUpload and removing/canceling the task (adding its taskId to canceledTasks) while computeFileFingerprint(file, name) is still running, before taskMd5Map.set(taskId, md5) executes.","commonSituations":"User clicks remove/cancel on a file row in the publish manage upload list while the md5 fingerprint of a large file is being computed; rapid cancel after enqueue; component unmount cleanup canceling in-flight enqueues.","solutions":["Treat DOMException with name 'AbortError' and message 'Upload canceled' as an expected cancel signal: swallow it or update task state to 'canceled', do not surface it as an error toast.","Ensure cancel actions set the task's UI status to canceled before/independent of the queue throwing, so the user sees consistent state.","If you need the upload to proceed, do not add the taskId to canceledTasks; check membership only after the user confirms cancel.","On unmount, clear pending tasks deliberately and suppress AbortError logging to avoid noisy console errors."],"exampleFix":"// before\ntask.cancel = () => canceledTasks.add(taskId)\nawait enqueueUpload(file) // rejects with 'Upload canceled'\n\n// after\ntry {\n  await enqueueUpload(file)\n}\ncatch (e) {\n  if (e instanceof DOMException && e.name === 'AbortError') {\n    updateTaskStatus(taskId, 'canceled')\n    return\n  }\n  throw e\n}","handlingStrategy":"try-catch","validationCode":"// no cheap pre-check: the cancel can land at any async checkpoint\nconst isCanceled = (taskId: string) => canceledTasks.has(taskId)\nif (isCanceled(taskId)) return // skip enqueue entirely when already canceled","typeGuard":"function isAbortError(e: unknown): e is DOMException {\n  return e instanceof DOMException && e.name === 'AbortError'\n}","tryCatchPattern":"try {\n  await enqueueUpload(file)\n}\ncatch (e) {\n  if (isAbortError(e)) { markTaskCanceled(taskId); return }\n  throw e\n}","preventionTips":["Check canceledTasks before starting fingerprinting to skip already-canceled tasks cheaply","Propagate an AbortSignal into computeFileFingerprint so cancellation aborts mid-hash","Keep task UI state and canceledTasks in sync in one updateTaskCanceled helper","Never log AbortError as an error level event; treat as user intent"],"tags":["upload","abort","user-cancel","react"],"backgroundTag":"operation-aborted","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}