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
- 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
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
- 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
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.