yikart/AiToEarn · error · BadRequestException

video duration is required

Error message

video duration is required

What it means

resolveVideoDuration must know the source video's duration for video2video tasks. It probes the video's metadata; if the probe fails or returns a non-positive/non-numeric duration and no explicit duration or default exists, it throws BadRequestException('video duration is required').

Source

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

    if (!Number.isFinite(maxDuration)) {
      throw new AppException(ResponseCode.InvalidModel)
    }
    return maxDuration
  }

  private async resolveVideoDuration(request: UserVideoGenerationRequestDto, modelConfig: DashscopeModelConfig, videoUrl: string | undefined): Promise<number | undefined> {
    if (request.duration != null) {
      return request.duration
    }

    if (!videoUrl) {
      return modelConfig.defaults.duration
    }

    const metadata = await this.videoMetadataService.probeVideoMetadata(FileUtil.buildUrl(videoUrl))
    const metadataDuration = Number(metadata.duration)
    if (!Number.isFinite(metadataDuration) || metadataDuration <= 0) {
      throw new BadRequestException('video duration is required')
    }

    return Math.min(Math.ceil(metadataDuration), this.getMaxDuration(modelConfig))
  }

  private async buildPayload(request: UserVideoGenerationRequestDto, modelConfig: DashscopeModelConfig): Promise<{
    providerModel: string
    mode: string
    payload: DashscopeCreateVideoTaskRequest
    duration?: number
    resolution?: string
  }> {
    if (request.image_tail) {
      throw new BadRequestException('DashScope HappyHorse does not support image_tail')
    }

    const imageUrls = this.collectImageUrls(request)
    const videoUrl = request.video_url ?? request.videos?.[0]

View on GitHub (pinned to d3aa8bea5b)

Solutions

  1. Pass an explicit duration in the request to skip metadata probing.
  2. Verify the video URL is accessible from the backend and the file plays correctly.
  3. Re-encode the video (e.g. with ffmpeg) so it carries proper duration metadata.
  4. Set modelConfig.defaults.duration so a default is used when probing fails.

Example fix

// before
POST /video/generate { model: '...', video_url: 'https://.../clip.mov' }
// after
POST /video/generate { model: '...', video_url: 'https://.../clip.mp4', duration: 5 }
Defensive patterns

Strategy: validation

Validate before calling

if (request.video_url && request.duration == null) {
  const meta = await probeVideoMetadata(request.video_url)
  if (!Number.isFinite(Number(meta.duration)) || Number(meta.duration) <= 0) {
    throw new Error('Source video has no readable duration; pass request.duration explicitly')
  }
}

Type guard

null

Try / catch

try {
  await generate(request)
} catch (err) {
  if (err instanceof BadRequestException && err.message === 'video duration is required') {
    // re-probe the video, re-encode it, or ask the user to supply a duration
  }
  throw err
}

Prevention

When it happens

Trigger: video2video request without request.duration and without modelConfig.defaults.duration, where probing videoUrl yields no usable duration (corrupt/unreadable file, unsupported codec, unreachable URL, or a 0-second/empty video).

Common situations: Uploaded video has no duration metadata (e.g. raw stream or live recording); storage URL not accessible from the backend so the probe returns nothing; video file truncated on upload.

Related errors


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