{"record":{"id":"ffeac6987351d80a","repo":"yikart/AiToEarn","slug":"invalidaitaskid-ffeac6","errorCode":"InvalidAiTaskId","errorMessage":"ResponseCode.InvalidAiTaskId","messagePattern":"ResponseCode\\.InvalidAiTaskId","errorType":"error_code","errorClass":"AppException","httpStatus":null,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/relay/relay-video.service.ts","lineNumber":132,"sourceCode":"\n  private normalizeStatus(status: string | undefined): TaskStatus {\n    if (!status) {\n      return TaskStatus.InProgress\n    }\n    const normalized = status.toLowerCase()\n    if (['success', 'succeeded', 'completed', 'succeed'].includes(normalized)) {\n      return TaskStatus.Success\n    }\n    if (['failed', 'error', 'failure'].includes(normalized)) {\n      return TaskStatus.Failure\n    }\n    return TaskStatus.InProgress\n  }\n\n  async callback(result: RelayVideoCallbackDto): Promise<RelayVideoCallbackDto> {\n    const taskId = result.id\n    if (!taskId) {\n      throw new AppException(ResponseCode.InvalidAiTaskId)\n    }\n    const aiLog = await this.aiLogRepo.getByTaskId(taskId)\n    if (!aiLog || aiLog.channel !== AiLogChannel.Relay) {\n      throw new AppException(ResponseCode.InvalidAiTaskId)\n    }\n    const relayAiLog = aiLog as RelayVideoAiLog\n\n    if (relayAiLog.status !== AiLogStatus.Generating) {\n      return relayAiLog.response!\n    }\n\n    const status = this.normalizeStatus(result.status)\n    if (status === TaskStatus.InProgress) {\n      return { ...result, id: taskId }\n    }\n\n    const elapsedMs = Date.now() - relayAiLog.startedAt.getTime()\n","sourceCodeStart":114,"sourceCodeEnd":150,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/relay/relay-video.service.ts#L114-L150","documentation":"InvalidAiTaskId thrown in RelayVideoService.callback when the callback payload has no id, or the id does not resolve to an existing Relay-channel AI log. Callbacks from the Relay upstream must reference a task this system created; anything else is rejected.","triggerScenarios":"line 132: result.id is falsy (callback body missing the task id field).","commonSituations":"Relay upstream sends a malformed/empty callback (e.g. error notification without id); a manually crafted or test callback POST omitted the id field; schema drift after a Relay version update changed the field name (e.g. taskId vs id).","solutions":["Ensure the callback producer includes the task id in the id field of the POST body","Verify the Relay callback contract/field names after any Relay version update","Filter or discard upstream notifications that lack an id instead of forwarding them to the callback endpoint","Log the raw callback body to identify malformed senders"],"exampleFix":"// before (caller)\nawait relayVideoService.callback({ status: 'done' })\n// after\nif (raw.id) await relayVideoService.callback({ ...raw, id: raw.id })","handlingStrategy":"validation","validationCode":"if (!callbackBody.id || typeof callbackBody.id !== 'string') {\n  // reject/ignore malformed callback before invoking the service\n  return\n}","typeGuard":"function isRelayCallback(b: unknown): b is RelayVideoCallbackDto {\n  return typeof b === 'object' && b !== null && typeof (b as any).id === 'string' && (b as any).id.length > 0\n}","tryCatchPattern":"try {\n  await relayVideoService.callback(body)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.InvalidAiTaskId) {\n    // log raw body, return 200/ignored so Relay stops retrying a permanently invalid callback\n  } else throw e\n}","preventionTips":["Validate the callback body schema at the webhook boundary","Confirm Relay's callback field names after version upgrades","Drop notifications without an id at ingress","Log unparseable callback payloads for upstream debugging"],"tags":["relay","callback","invalid-task-id","webhook"],"backgroundTag":"invalid-callback-task-id","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}