{"record":{"id":"8778678d474f00a2","repo":"yikart/AiToEarn","slug":"responsecode-assetnotfound","errorCode":"ResponseCode.AssetNotFound","errorMessage":"AssetNotFound","messagePattern":"AssetNotFound","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/libs/assets/src/assets.service.ts","lineNumber":201,"sourceCode":"      mimeType: dto.mimeType,\n      filename: dto.filename,\n      metadata: dto.metadata,\n    })\n\n    return {\n      asset,\n      url: this.buildUrl(path),\n    }\n  }\n\n  async confirmUpload(dto: ConfirmAssetDto): Promise<Asset> {\n    if (this.options.maxSize != null && dto.size && dto.size >= this.options.maxSize) {\n      throw new AppException(ResponseCode.AssetTooLarge)\n    }\n    const asset = await this.assetRepository.getById(dto.assetId)\n\n    if (!asset) {\n      throw new AppException(ResponseCode.AssetNotFound)\n    }\n\n    if (asset.status !== AssetStatus.Pending) {\n      return asset\n    }\n\n    const updateData: Partial<Asset> = {\n      status: AssetStatus.Confirmed,\n    }\n\n    if (dto.size) {\n      updateData.size = dto.size\n    }\n\n    if (dto.metadata) {\n      updateData.metadata = { ...asset.metadata, ...dto.metadata }\n    }\n","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/libs/assets/src/assets.service.ts#L183-L219","documentation":"confirmUpload throws AssetNotFound when assetRepository.getById(dto.assetId) returns no asset. The client is confirming an upload whose pending-asset record does not exist in the database.","triggerScenarios":"Confirming with an assetId that was never created, was deleted, belongs to another environment/database, or a stale id cached client-side after the record was cleaned up.","commonSituations":"Retrying an old confirm call after the asset record expired/was purged, copying assetId between dev and prod, typo'd UUID, or the sign step actually failed earlier so no record exists.","solutions":["Verify dto.assetId matches a real asset row; re-run the upload-sign flow to obtain a fresh id","Check you are pointing at the correct database/environment","Handle AssetNotFound client-side by restarting the upload flow instead of retrying the same id","Log the assetId and query the asset table directly to confirm deletion"],"exampleFix":"// before\nawait confirmUpload({ assetId: staleId, size })\n// after\nconst { assetId } = await createUploadSign(userId, dto)\nawait doUpload(assetId)\nawait confirmUpload({ assetId, size })","handlingStrategy":"try-catch","validationCode":"const asset = await assetsApi.get(assetId) // or check the id exists locally\nif (!asset) throw new Error(`assetId ${assetId} unknown; re-run upload sign flow`)","typeGuard":"function isNonEmptyUuid(id: unknown): id is string {\n  return typeof id === 'string' && /^[0-9a-f-]{36}$/i.test(id)\n}","tryCatchPattern":"try {\n  await confirmUpload({ assetId, size })\n} catch (e) {\n  if (e.code === ResponseCode.AssetNotFound) {\n    const sign = await createUploadSign(userId, dto)\n    await doUpload(sign)\n    await confirmUpload({ assetId: sign.assetId, size })\n  } else throw e\n}","preventionTips":["Always obtain assetId from a fresh createUploadSign call, never cache across sessions","Don't share assetIds between environments","Clean up pending assets with a TTL long enough for slow clients","Log assetId on confirm failures to speed diagnosis"],"tags":["assets","not-found","database","upload"],"backgroundTag":"asset-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}