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
- Fetch the material list for the task and use a taskMaterialId from the current response
- Verify the material id actually belongs to the task being applied for (it must be findable via getTaskMaterialById)
- If the caller does not need a material, omit taskMaterialId entirely — the check only runs when it is truthy
- 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
- Always source taskMaterialId from a fresh material-list response, never cache it
- Omit taskMaterialId when the task has no material requirement
- Validate the id is a 24-char hex ObjectId before sending
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.