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
- Inspect the raw Relay createVideo response to confirm the id field name/shape matches what the interceptor reads
- Verify Relay credentials (RELAY_API_KEY / RELAY_SERVER_URL) and that the Relay service is healthy
- Add validation on the Relay library side to surface non-2xx or malformed envelopes as distinct errors
- 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
- Monitor Relay upstream for response schema changes
- Verify RELAY_API_KEY/RELAY_SERVER_URL health before large batches
- Log full raw Relay responses to diagnose empty ids
- Implement one safe retry for id-less responses
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.