yikart/AiToEarn · error · AppException

AiCallFailed

AiCallFailed

Error message

任务结果为空

What it means

Volcengine DirectEdit 的 getDirectEditResult 调用 GetDirectEditResult 后,processDirectEditResult 收到的 response.Result 为 null/undefined。库把『结果整体缺失』视为 AI 调用失败并抛出 AiCallFailed,而空数组被视为『任务处理中』返回 Processing 状态。也就是说,结果缺失(而不是结果未准备好)被认为是真正的异常。

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/libs/volcengine/services/direct-edit.service.ts:80

    this.checkApiResponseError(response, 'Submit direct edit task', requestData)

    return response.Result
  }

  /**
   * 处理剪辑任务查询结果
   * @param result API 返回的原始结果
   * @param reqId 请求的任务 ID
   * @returns 处理后的任务结果
   */
  private processDirectEditResult(
    result: GetDirectEditResultResponse | null | undefined,
    reqId: string,
  ): GetDirectEditResultItem {
    // 处理空结果
    if (!result) {
      this.logger.error({ reqId }, '[ProcessDirectEditResult] Result 为空')
      throw new AppException(ResponseCode.AiCallFailed, '任务结果为空')
    }

    // 如果 Result 是数组
    if (Array.isArray(result)) {
      if (result.length === 0) {
        // 任务刚提交,火山引擎还没准备好数据,返回处理中状态
        this.logger.debug({ reqId }, '[ProcessDirectEditResult] 任务结果为空数组,任务可能刚提交还在准备中')
        return {
          TaskId: reqId,
          ReqId: reqId,
          Application: 'VideoTrackToB',
          Status: 'Processing',
        }
      }

      return result[0]
    }

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. 打印 reqId 和完整响应体,确认 Result 确实缺失而不是类型断言错误。
  2. 核对 ReqId 是否来自同一次 SubmitDirectEditTaskAsync 的返回且 SpaceName 一致。
  3. 对『任务刚提交』的场景重试查询:空数组会返回 Processing,但 null 不行,需要调用方自行重试。
  4. 若持续为空,登录火山 VOD 控制台按 ReqId/TaskId 查任务是否仍存在。

Example fix

// before
const item = await directEditService.getDirectEditResult({ ReqIds: [reqId] })
// after
let item: GetDirectEditResultItem | null = null
for (let i = 0; i < 5; i++) {
  try {
    item = await directEditService.getDirectEditResult({ ReqIds: [reqId] })
    break
  } catch (e) {
    if (isAiCallFailed(e) && e.message === '任务结果为空') {
      await sleep(3000)
      continue
    }
    throw e
  }
}
if (!item) throw new Error(`Direct edit result unavailable for ${reqId}`)
Defensive patterns

Strategy: retry

Validate before calling

if (!reqId || typeof reqId !== 'string') throw new Error('Valid ReqId required before polling GetDirectEditResult')

Type guard

function hasDirectEditResult(r: unknown): r is { Result: unknown[] | object } {
  return r != null && typeof r === 'object' && 'Result' in r && r.Result != null
}

Try / catch

try {
  const item = await getDirectEditResult({ ReqIds: [reqId] })
  if (item.Status === 'Processing') return scheduleRetry(reqId)
} catch (e) {
  if (isAiCallFailed(e) && e.message === '任务结果为空') return scheduleRetry(reqId)
  throw e
}

Prevention

When it happens

Trigger: 调用 getDirectEditResult({ ReqIds: [...] }) 时,火山引擎 VOD API 返回了无 Error 的响应但 Result 字段为 null/undefined:例如 ReqId 无效或已过期、任务在火山侧被删除、响应被网关截断,或 Result 缺少 Result 字段。

Common situations: 在任务提交后过早且只查了一次就假设有结果;ReqId 拼写错误或来自另一个 SpaceName;火山引擎返回了 200 但 body 结构与 SDK 类型不符(API 版本变更);代理/网关剥掉了字段。

Related errors


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