yikart/AiToEarn · error · AppException

AiCallFailed

AiCallFailed

Error message

Relay task id is missing

What it means

AiCallFailed with detail 'Relay task id is missing' is thrown by RelayVideoService.createFromRequest when the upstream Relay createVideo call succeeded (or returned) without an id. The service extracts result.id via a response interceptor and treats an empty id as a failed Relay call since no task can be tracked without it.

Source

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

    }
    const startedAt = new Date()

    const payload = { ...request } as RelayVideoGenerationRequest & { userId?: string, userType?: UserType, groupId?: string }
    delete payload.userId
    delete payload.userType
    delete payload.groupId

    const relayPayload = await this.resolveRelayJson(payload)

    const result = await this.aiAvailability.executeAsync<RelayVideoSubmitResponse>(
      { provider: 'relay', operation: 'videoGeneration', model: request.model },
      () => this.relayLibService.createVideo(relayPayload),
      response => response.id || '',
    )

    const remoteTaskId = result.id
    if (!remoteTaskId) {
      throw new AppException(ResponseCode.AiCallFailed, { error: 'Relay task id is missing' })
    }

    const logRequest: RelayVideoAiLog['request'] = {
      ...payload,
      remoteTaskId,
    }
    if (request.groupId) {
      logRequest.groupId = request.groupId
    }

    const aiLog = await this.aiLogRepo.create({
      userId: request.userId,
      userType: request.userType,
      taskId: remoteTaskId,
      model: request.model,
      channel: AiLogChannel.Relay,
      startedAt,
      type: AiLogType.Video,

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Inspect the raw Relay createVideo response to confirm the id field name/shape matches what the interceptor reads
  2. Verify Relay credentials (RELAY_API_KEY / RELAY_SERVER_URL) and that the Relay service is healthy
  3. Add validation on the Relay library side to surface non-2xx or malformed envelopes as distinct errors
  4. Retry the creation; if persistent, report the payload to Relay support and check for API version changes

Example fix

// before (library interceptor)
response => response.id || ''
// after
response => {
  if (!response?.id) throw new Error(`Relay createVideo returned no id: ${JSON.stringify(response)}`)
  return response.id
}
Defensive patterns

Strategy: retry

Validate before calling

// no pre-call check possible; validate after the call
const id = response?.id
if (typeof id !== 'string' || id.length === 0) throw new Error('Relay returned no task id')

Type guard

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

Try / catch

try {
  const { id } = await relayVideoService.createFromRequest(req)
} catch (e) {
  if (e instanceof AppException && e.code === ResponseCode.AiCallFailed) {
    // inspect e.meta.error ('Relay task id is missing'), check Relay health/credentials, retry once
  } else throw e
}

Prevention

When it happens

Trigger: The relayLibService.createVideo(relayPayload) response resolved but its id field was empty/undefined, so `if (!remoteTaskId)` fired.

Common situations: Relay upstream changed its response schema (id renamed or nested); Relay returned a 2xx error envelope without an id; network proxy stripped the body; Relay-side quota/auth failure surfaced as a success-shaped empty response; timeout handling returned a partial object.

Related errors


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