harry0703/MoneyPrinterTurbo · error · ElevenLabsMusicError

ElevenLabs video duration is invalid

Error message

ElevenLabs video duration is invalid

What it means

First of two duration validation branches in generate_bgm: float(video_duration) raised TypeError (input was None or a non-numeric object) or ValueError (input was a string like '' or 'abc'). The value is coerced because task queues often deliver durations as strings.

Source

Thrown at app/services/elevenlabs_music.py:377

    finally:
        _remove_file(temp_audio_path)


def generate_bgm(
    video_path: str,
    output_path: str,
    video_duration: float,
    prompt: str = "",
) -> str:
    """为一条已拼接视频生成时长和画面匹配的 ElevenLabs 背景音乐。"""
    if not get_api_key():
        raise ElevenLabsMusicError("ElevenLabs API key is required")
    if not os.path.isfile(video_path):
        raise ElevenLabsMusicError("ElevenLabs input video does not exist")
    try:
        duration = float(video_duration)
    except (TypeError, ValueError) as exc:
        raise ElevenLabsMusicError(
            "ElevenLabs video duration is invalid"
        ) from exc
    if not math.isfinite(duration) or duration <= 0:
        raise ElevenLabsMusicError("ElevenLabs video duration is invalid")
    if duration > MAX_VIDEO_DURATION_SECONDS:
        raise ElevenLabsMusicError(
            "ElevenLabs supports videos up to 600 seconds"
        )
    prompt = str(prompt or "").strip()
    if len(prompt) > MAX_PROMPT_LENGTH:
        raise ElevenLabsMusicError(
            "ElevenLabs music prompt exceeds 1000 characters"
        )

    proxy_path = ""
    try:
        proxy_path = _create_video_proxy(video_path)
        return _request_bgm(proxy_path, output_path, prompt)

View on GitHub (pinned to 1f9f19c202)

Solutions

  1. Fix the upstream duration source: re-run ffprobe on the concatenated video and check why it returned a non-numeric value
  2. Coerce to float before queueing the job: float(video_duration) at enqueue time surfaces the bug where it happens
  3. Log the raw value and its type when this fires so the offending producer is identifiable

Example fix

# before
generate_bgm(video, out, duration_from_queue, prompt)  # duration_from_queue = '' 

# after
duration = float(ffprobe_duration(video))  # raises at the producer, not in the task
if not duration > 0:
    raise ValueError(f"bad duration for {video}")
generate_bgm(video, out, duration, prompt)
Defensive patterns

Strategy: validation

Validate before calling

duration = float(video_duration)  # coerce at enqueue; raises at the producer
assert duration > 0

Type guard

def is_parseable_duration(v) -> bool:
    try:
        float(v)
        return True
    except (TypeError, ValueError):
        return False

Prevention

When it happens

Trigger: video_duration is None (upstream ffprobe failed and returned None), a string that is not parseable as a float, or an object whose __float__ raises.

Common situations: ffprobe failed silently and None propagated into the BGM task, JSON task payloads carrying an empty string for duration, or a refactor changing the duration type from float to a dataclass the code does not expect.

Related errors


AI-assisted analysis of harry0703/MoneyPrinterTurbo@1f9f19c202 (2026-08-14). Data as JSON: /api/errors/0505d3b836e859a2. Report an issue: GitHub.