yikart/AiToEarn · error · AppException

AiCallFailed

AiCallFailed

Error message

AiCallFailed

What it means

drama-recap.service.ts 的 getDramaRecapTask 查询短剧解说任务时,若响应 ResponseMetadata.Error 存在(火山引擎业务级错误,如无效任务 ID、权限、限流),则统一包装为 AiCallFailed 抛出,附原始 Code 和 Message。

Source

Thrown at project/aitoearn-backend/apps/aitoearn-ai/src/core/ai/libs/volcengine/services/drama-recap.service.ts:79

    request: QueryDramaRecapTaskRequest,
  ): Promise<QueryDramaRecapTaskResponse> {
    const api = this.vodService.createAPI<
      QueryDramaRecapTaskRequest,
      QueryDramaRecapTaskResponse
    >('QueryDramaRecapTask', {
      Version: '2025-03-03',
      method: 'GET',
      contentType: 'json',
    })
    const response = await api(request)
    // 检查 API 响应中的错误
    if (response.ResponseMetadata?.Error) {
      const error = response.ResponseMetadata.Error
      this.logger.error(
        { error, requestData: request },
        `QueryDramaRecapTask failed: ${error.Code || 'Unknown'} - ${error.Message}`,
      )
      throw new AppException(ResponseCode.AiCallFailed, {
        code: error.Code || 'Unknown',
        message: error.Message,
      })
    }

    // 对于短剧解说任务,Result 可能为空(任务刚提交还在准备中)
    // 返回一个默认的处理中状态,让上层继续轮询
    if (!response.Result) {
      this.logger.debug({ taskId: request.TaskId }, '[getDramaRecapTask] Result 为空,任务可能还在准备中')
      return {
        TaskId: request.TaskId,
        Status: DramaRecapTaskStatus.Processing,
      }
    }

    return response.Result
  }
}

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. 读取异常 data 中的 code/message(如 InvalidTaskId、SignatureDoesNotMatch),按具体错误处理。
  2. 核对 VolcengineConfig 中 accessKeyId/secretAccessKey 及对应服务开通状态。
  3. 确认 TaskId 来自 createDramaRecapTask 的返回且仍在有效期内。
  4. 对限流类错误(RequestLimitExceeded 等)加指数退避重试。

Example fix

// before
const res = await volcengineService.getDramaRecapTask({ TaskId })
// after
try {
  const res = await volcengineService.getDramaRecapTask({ TaskId })
} catch (e) {
  const code = (e as any)?.data?.code
  if (code === 'RequestLimitExceeded') return retryWithBackoff()
  throw e
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!taskId) throw new Error('TaskId is required')
// env check
for (const k of ['VOLC_ACCESS_KEY_ID', 'VOLC_SECRET_ACCESS_KEY']) {
  if (!process.env[k]) throw new Error(`Missing env ${k}`)
}

Type guard

function hasVolcengineError(r: unknown): r is { ResponseMetadata: { Error: { Code: string, Message: string } } } {
  return r != null && typeof r === 'object'
    && !!(r as any).ResponseMetadata?.Error
}

Try / catch

try {
  const res = await getDramaRecapTask({ TaskId })
} catch (e) {
  const code = (e as any)?.data?.code
  if (code === 'RequestLimitExceeded') return retryWithBackoff()
  if (code === 'InvalidTaskId' || code === 'ResourceNotFound') return markTaskFailed(taskId)
  throw e
}

Prevention

When it happens

Trigger: 调用 getDramaRecapTask(或已废弃的 queryDramaRecapTask)时火山返回带 ResponseMetadata.Error 的响应,例如 QueryDramaRecapTask 的 TaskId 不存在、AK/SK 权限不足、签名错误、配额/限流 InvalidRequest 或 InternalError。

Common situations: AK/SK 配置错误或未开通短剧解说权限;查询尚未提交成功的 TaskId;账号被限流;火山侧服务故障;任务属于其他 Region/账号。

Related errors


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