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

  1. Inspect confirmResponse.code/message for the server-side reason.
  2. Re-authenticate and retry confirmUpload alone — the file is already in OSS, no need to re-upload.
  3. Verify assetId comes from the presignedData response unchanged.
  4. 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

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.