yikart/AiToEarn · error · NotFoundException

任务素材不存在

Error message

任务素材不存在

What it means

HTTP 404 NotFoundException thrown by POST task-apply when body.taskMaterialId is provided but no TaskMaterial document with that id exists. The controller checks the task first, then resolves the referenced material before creating the user-task application. It exists to guarantee every application references a real material record.

Source

Thrown at project/aitoearn-electron/server/src/modules/task/task.controller.ts:88

    return await this.taskService.findOne(id);
  }

  @ApiOperation({ summary: '申请任务: 保持一定时间' })
  @ApiResult({ type: Boolean })
  @Post('apply/:id')
  async applyForTask(
    @Param('id') id: string,
    @GetToken() token: TokenInfo,
    @Body() body: ApplyTaskDto,
  ) {
    const task = await this.taskService.findOne(id);
    if (!task) throw new NotFoundException('任务不存在');

    if (!!body.taskMaterialId) {
      const taskMaterial = await this.taskService.getTaskMaterialById(
        body.taskMaterialId,
      );
      if (!taskMaterial) throw new NotFoundException('任务素材不存在');
    }

    const res = await this.userTaskService.userApplyTask(token.id, task, body);

    if (!!body.taskMaterialId)
      this.taskService.upTaskMaterialUsedCount(body.taskMaterialId);

    return res;
  }

  @ApiOperation({ summary: '提交任务 id是用户任务ID' })
  @ApiResult({ type: Boolean })
  @Post('submit/:id')
  async submitTask(
    @GetToken() token: TokenInfo,
    @Param('id') id: string,
    @Body() data: SubmitTaskDto,
  ) {

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Fetch the material list for the task and use a taskMaterialId from the current response
  2. Verify the material id actually belongs to the task being applied for (it must be findable via getTaskMaterialById)
  3. If the caller does not need a material, omit taskMaterialId entirely — the check only runs when it is truthy
  4. Confirm MongoDB connectivity if a known-good id suddenly 404s

Example fix

// before
await api.applyForTask(taskId, { taskMaterialId: '64a1b2c3' }) // stale id
// after
const task = await api.getTask(taskId)
await api.applyForTask(taskId, { taskMaterialId: task.materials[0].id })
Defensive patterns

Strategy: validation

Validate before calling

const materials = await api.getTaskMaterials(taskId)
if (!materials.some(m => m.id === body.taskMaterialId)) {
  throw new Error('Invalid taskMaterialId for this task')
}

Type guard

function hasValidMaterialId(body: unknown): body is { taskMaterialId: string } {
  return typeof (body as any)?.taskMaterialId === 'string' && /^[a-f\d]{24}$/i.test((body as any).taskMaterialId)
}

Try / catch

try {
  await api.applyForTask(taskId, body)
} catch (e) {
  if (e?.status === 404 && e?.message === '任务素材不存在') {
    // refresh material list and re-pick a valid taskMaterialId
  } else throw e
}

Prevention

When it happens

Trigger: POST to the task apply endpoint with a body containing taskMaterialId that does not match any taskMaterial document: a stale/hardcoded id, an id from a deleted material, an id belonging to another task, or a malformed ObjectId.

Common situations: Client caches material ids after an admin deletes/recreates materials; tester copies a request sample with a made-up taskMaterialId; frontend passes the task id instead of the material id.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of yikart/AiToEarn@d3aa8bea5b (2026-08-31). Data as JSON: /api/errors/ed7d0b1ee4b46e66. Report an issue: GitHub.