yikart/AiToEarn · error · AppException

InvalidAiTaskId

InvalidAiTaskId

Error message

ResponseCode.InvalidAiTaskId

What it means

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.

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/video/relay/relay-video.service.ts:132

  private normalizeStatus(status: string | undefined): TaskStatus {
    if (!status) {
      return TaskStatus.InProgress
    }
    const normalized = status.toLowerCase()
    if (['success', 'succeeded', 'completed', 'succeed'].includes(normalized)) {
      return TaskStatus.Success
    }
    if (['failed', 'error', 'failure'].includes(normalized)) {
      return TaskStatus.Failure
    }
    return TaskStatus.InProgress
  }

  async callback(result: RelayVideoCallbackDto): Promise<RelayVideoCallbackDto> {
    const taskId = result.id
    if (!taskId) {
      throw new AppException(ResponseCode.InvalidAiTaskId)
    }
    const aiLog = await this.aiLogRepo.getByTaskId(taskId)
    if (!aiLog || aiLog.channel !== AiLogChannel.Relay) {
      throw new AppException(ResponseCode.InvalidAiTaskId)
    }
    const relayAiLog = aiLog as RelayVideoAiLog

    if (relayAiLog.status !== AiLogStatus.Generating) {
      return relayAiLog.response!
    }

    const status = this.normalizeStatus(result.status)
    if (status === TaskStatus.InProgress) {
      return { ...result, id: taskId }
    }

    const elapsedMs = Date.now() - relayAiLog.startedAt.getTime()

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Ensure the callback producer includes the task id in the id field of the POST body
  2. Verify the Relay callback contract/field names after any Relay version update
  3. Filter or discard upstream notifications that lack an id instead of forwarding them to the callback endpoint
  4. Log the raw callback body to identify malformed senders

Example fix

// before (caller)
await relayVideoService.callback({ status: 'done' })
// after
if (raw.id) await relayVideoService.callback({ ...raw, id: raw.id })
Defensive patterns

Strategy: validation

Validate before calling

if (!callbackBody.id || typeof callbackBody.id !== 'string') {
  // reject/ignore malformed callback before invoking the service
  return
}

Type guard

function isRelayCallback(b: unknown): b is RelayVideoCallbackDto {
  return typeof b === 'object' && b !== null && typeof (b as any).id === 'string' && (b as any).id.length > 0
}

Try / catch

try {
  await relayVideoService.callback(body)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.InvalidAiTaskId) {
    // log raw body, return 200/ignored so Relay stops retrying a permanently invalid callback
  } else throw e
}

Prevention

When it happens

Trigger: line 132: result.id is falsy (callback body missing the task id field).

Common situations: 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).

Related errors


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