{"record":{"id":"c634b03cec0bafe6","repo":"yikart/AiToEarn","slug":"error-c634b0","errorCode":null,"errorMessage":"任务状态不正确","messagePattern":"任务状态不正确","errorType":"http","errorClass":"NotFoundException","httpStatus":404,"severity":"error","filePath":"project/aitoearn-electron/server/src/modules/task/task.controller.ts","lineNumber":145,"sourceCode":"    }\n\n    return res;\n  }\n\n  // 任务提现（创建提现数据）\n  @ApiOperation({ summary: '用户任务提现' })\n  @ApiResult({ type: Boolean })\n  @Post('withdraw/:id')\n  async withdrawCashUserTask(\n    @GetToken() token: TokenInfo,\n    @Param('id') id: string,\n    @Body() data: { accountId: string },\n  ) {\n    const userTask = await this.userTaskService.getUserTaskInfoById(id);\n    if (!userTask || userTask.userId.toString() !== token.id)\n      throw new NotFoundException('任务不存在');\n    if (userTask.status !== UserTaskStatus.APPROVED)\n      throw new NotFoundException('任务状态不正确');\n    const account = await this.financeService.getUserWalletAccountById(\n      data.accountId,\n    );\n    if (!account) throw new NotFoundException('钱包账户不存在');\n\n    return await this.financeService.createUserWalletRecord(token.id, account, {\n      dataId: userTask.id,\n      type: UserWalletRecordType.WITHDRAW,\n      balance: userTask.reward, // 将 number 转换为 Decimal128\n      des: '任务提现',\n      status: UserWalletRecordStatus.WAIT,\n    });\n  }\n\n  @ApiOperation({ summary: '统计合计进行中的任务的金额总数' })\n  @Get('reward/amount')\n  @ApiResult({ type: Number })\n  async getTotalAmountOfDoingTasks(@GetToken() token: TokenInfo) {","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-electron/server/src/modules/task/task.controller.ts#L127-L163","documentation":"HTTP 404 NotFoundException '任务状态不正确' thrown when the userTask exists and is owned by the caller, but its status is not UserTaskStatus.APPROVED (task.controller.ts:145). Withdrawals are only allowed on approved tasks, so status gating reuses 404 here.","triggerScenarios":"Calling the withdraw-cash endpoint while the userTask is PENDING, DODING, or REJECTED — i.e. before the task submission has been approved by the auditor.","commonSituations":"User tries to withdraw right after submitting, before admin approval; automated client retries withdrawal without re-checking status; task was approved then reset to a different status.","solutions":["Only withdraw after the task status is APPROVED — poll the userTask status first","Handle the approval notification/event before triggering withdrawal","If the task should be approved, contact the task admin/auditor rather than retrying","Surface the current status to the user in the UI instead of blindly calling withdraw"],"exampleFix":"// before\nawait api.withdrawCash(userTask.id, { accountId }) // status may be PENDING\n// after\nconst ut = await api.getUserTaskInfo(userTask.id)\nif (ut.status === 'APPROVED') await api.withdrawCash(userTask.id, { accountId })","handlingStrategy":"validation","validationCode":"const ut = await api.getUserTaskInfo(userTaskId)\nif (ut.status !== 'APPROVED') {\n  throw new Error(`Withdrawal requires APPROVED status, current: ${ut.status}`)\n}","typeGuard":"function isApproved(ut: UserTask): boolean {\n  return ut.status === 'APPROVED'\n}","tryCatchPattern":"try {\n  await api.withdrawCash(userTaskId, { accountId })\n} catch (e) {\n  if (e?.status === 404 && e?.message === '任务状态不正确') {\n    // poll status until APPROVED or show waiting-for-approval UI\n  } else throw e\n}","preventionTips":["Gate withdrawal UI on the APPROVED status from the server, not local state","Do not auto-retry withdrawal; the state will not change without auditor approval","Surface task audit status changes to the user via notifications"],"tags":["http-404","state-machine","validation"],"backgroundTag":"invalid-resource-state","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}