{"record":{"id":"5ce76baeab5b9d1e","repo":"yikart/AiToEarn","slug":"aicallfailed-5ce76b","errorCode":"AiCallFailed","errorMessage":"Relay video task id is missing: ${this.stringifyForError(result)}","messagePattern":"Relay video task id is missing: (.+?)","errorType":"error_code","errorClass":"AppException","httpStatus":400,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/libs/relay/relay.service.ts","lineNumber":93,"sourceCode":"      return String(value)\n    }\n  }\n\n  /**\n   * 提交视频生成任务到上游 relay 服务端\n   * 对应上游 POST /ai/video/generations\n   */\n  async createVideo(request: RelayVideoGenerationRequest): Promise<RelayVideoSubmitResponse> {\n    return this.aiAvailability.execute(\n      { provider: 'relay', operation: 'createVideo', model: request.model },\n      async () => {\n        const response: AxiosResponse<RelayVideoSubmitResponse> = await this.httpClient.post(\n          '/api/ai/video/generations',\n          request,\n        )\n        const result = response.data\n        if (!result?.id) {\n          throw new AppException(ResponseCode.AiCallFailed, { error: `Relay video task id is missing: ${this.stringifyForError(result)}` })\n        }\n        return result\n      },\n    )\n  }\n\n  /**\n   * 轮询上游 relay 服务端的视频任务状态\n   * 对应上游 GET /ai/video/generations/:taskId\n   */\n  async getVideo(taskId: string): Promise<RelayVideoCallbackDto> {\n    return this.aiAvailability.execute(\n      { provider: 'relay', operation: 'getVideo' },\n      async () => {\n        const response: AxiosResponse<RelayVideoCallbackDto> = await this.httpClient.get(\n          `/api/ai/video/generations/${encodeURIComponent(taskId)}`,\n        )\n        return response.data","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/libs/relay/relay.service.ts#L75-L111","documentation":"createVideo posts to the relay endpoint /api/ai/video/generations and requires the response to include a task id (result.id) for later polling. If the relay accepted the request but the body lacks an id (or the body is empty/unexpected shape), it throws AppException(AiCallFailed) including the stringified response body for debugging.","triggerScenarios":"Relay returns 200 with an unexpected body (error payload not caught earlier, HTML error page from a proxy, changed response schema), a gateway/timeouts middleware rewrites the response, or request params are silently ignored causing the relay to return an ack without a task.","commonSituations":"Relay service version mismatch with client expectations; proxy/load balancer intercepting the POST; API contract change on /api/ai/video/generations; environment misconfiguration routing to the wrong relay host.","solutions":["Inspect the stringified result embedded in the error to see what the relay actually returned","Verify RELAY_SERVER_URL points to the correct environment and the video endpoint exists there (cn: https://aitoearn.cn/api, intl: https://aitoearn.ai/api)","Check relay service health/changelog for a response schema change to RelayVideoSubmitResponse","Confirm the submitted request passes relay-side validation (model, duration, etc.) so it truly enqueues a task"],"exampleFix":"// before\nconst result = await relayService.createVideo(request) // throws AiCallFailed if id missing\n// after\ntry {\n  const result = await relayService.createVideo(request)\n} catch (e) {\n  logger.error({ detail: e }, 'relay createVideo returned no task id')\n  throw new ServiceUnavailableException('Video task could not be created at relay; see server logs')\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const task = await relayService.createVideo(req)\n} catch (e) {\n  if (e instanceof AppException && e.code === ResponseCode.AiCallFailed && String(e.message).includes('task id is missing')) {\n    logger.error({ detail: e.message }, 'relay video submit returned no id')\n    throw new ServiceUnavailableException('Video task submission failed at relay')\n  }\n  throw e\n}","preventionTips":["Pin and monitor relay service versions for response contract changes","Verify RELAY_SERVER_URL hosts the video endpoint before rollout","Alert on any createVideo failure — the embedded stringified body tells you what the relay returned","Ensure submit parameters pass relay validation so a task is actually enqueued"],"tags":["relay","video","contract"],"backgroundTag":"missing-task-id","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}