{"record":{"id":"ef6fcf2adfb104a3","repo":"yikart/AiToEarn","slug":"ailognotfound","errorCode":"AiLogNotFound","errorMessage":"ResponseCode.AiLogNotFound","messagePattern":"ResponseCode\\.AiLogNotFound","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts","lineNumber":170,"sourceCode":"  constructor(\n    private readonly materialGroupRepository: MaterialGroupRepository,\n    private readonly materialRepository: MaterialRepository,\n    private readonly aiLogRepository: AiLogRepository,\n    private readonly queueService: QueueService,\n    private readonly videoService: VideoService,\n    private readonly assetsService: AssetsService,\n    private readonly videoMetadataService: VideoMetadataService,\n    private readonly aiAvailability: AiAvailabilityService,\n    private readonly imageService: ImageService,\n    private readonly mediaRepository: MediaRepository,\n    private readonly draftGenerationPlannerService: DraftGenerationPlannerService,\n    private readonly draftGenerationMemoryService: DraftGenerationMemoryService,\n  ) { }\n\n  async getTask(taskId: string, userId: string, userType: UserType) {\n    const aiLog = await this.aiLogRepository.getByIdAndUserId(taskId, userId, userType)\n    if (!aiLog) {\n      throw new AppException(ResponseCode.AiLogNotFound)\n    }\n    return await this.attachQueueInfo(aiLog)\n  }\n\n  async listTasks(dto: QueryDraftGenerationTasksDto, userId: string, userType: UserType) {\n    const tasks = await this.aiLogRepository.listByIdsAndUserId(dto.taskIds, userId, userType)\n    return await this.attachQueueInfoToTasks(tasks)\n  }\n\n  async listTasksWithPagination(dto: ListDraftGenerationTasksDto, userId: string, userType: UserType) {\n    const [tasks, total] = await this.aiLogRepository.listWithPagination({\n      ...dto,\n      userId,\n      userType,\n      type: AiLogType.DraftGeneration,\n    })\n    return [await this.attachQueueInfoToTasks(tasks), total] as const\n  }","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/draft-generation/draft-generation.service.ts#L152-L188","documentation":"DraftGenerationService.getTask fetches an AI log by id AND (userId, userType) via aiLogRepository.getByIdAndUserId; when no document matches, it throws AppException(ResponseCode.AiLogNotFound). The ownership scoping means a valid task id belonging to another user is indistinguishable from a nonexistent id.","triggerScenarios":"Polling a draft-generation task with a taskId that does not exist, was created by a different userId/userType, or with a JWT/auth context whose userType differs from the one recorded on the log (e.g. querying as user vs admin/agent type).","commonSituations":"Client polls with a task id from a previous environment/database; auth token rotated so the userId no longer matches the log owner; task id truncated or type-confused (stringified ObjectId vs custom id); calling getTask before task creation was persisted.","solutions":["Verify the taskId belongs to the authenticated userId/userType making the request","Re-create the task if the id came from another environment or expired retention window","Confirm the userType in the auth context matches the one used at task creation","Handle AiLogNotFound in the polling client as a terminal 'task unknown' state instead of retrying forever"],"exampleFix":"// before\nconst task = await getTask(taskId, currentUserId, UserType.User) // taskId owned by another user\n// after\nconst ownedTaskIds = (await listTasks({ taskIds: [taskId] }, currentUserId, UserType.User))\nif (!ownedTaskIds.length) throw new AppException(ResponseCode.AiLogNotFound) // fail fast client-side, don't poll foreign ids","handlingStrategy":"try-catch","validationCode":"// client-side: only poll ids returned by your own create call, persisted with the same auth context\nif (!createdTaskIds.includes(taskId)) {\n  throw new Error(`taskId ${taskId} was not created by this user/session`)\n}","typeGuard":null,"tryCatchPattern":"try {\n  const task = await draftGenerationService.getTask(taskId, userId, userType)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.AiLogNotFound) {\n    return { status: 'unknown' } // stop polling; do not retry\n  }\n  throw e\n}","preventionTips":["Treat AiLogNotFound as terminal when polling — the id is foreign or expired, retrying won't help","Ensure the userType in the request auth context matches the one used at task creation","Handle token/user rotation: re-derive userId from the current auth, not cached values","Never share task ids across environments; ids are database- and user-scoped"],"tags":["not-found","ownership","authorization","task-polling"],"backgroundTag":"resource-not-found","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}