MiniMax-AI/skills · error · SystemExit

No download_url in response: {json.dumps(data, indent=2)}

Error message

No download_url in response: {json.dumps(data, indent=2)}

What it means

download_video() called GET files/retrieve, got HTTP 200 + valid base_resp, but data['file']['download_url'] is missing or empty. The file_id may be invalid/expired, the file not yet ready, or the response contract changed. The full JSON is dumped for diagnosis.

Source

Thrown at skills/gif-sticker-maker/scripts/minimax_video.py:160

    raise SystemExit(f"Timeout after {max_wait}s. task_id={task_id}, check manually.")


def download_video(file_id: str, output_path: str):
    """Retrieve download URL via file_id and save the video."""
    resp = requests.get(
        f"{API_BASE}/files/retrieve",
        headers=_headers(),
        params={"file_id": file_id},
        timeout=30,
    )
    resp.raise_for_status()
    data = resp.json()
    _check_resp(data)

    download_url = data.get("file", {}).get("download_url", "")
    if not download_url:
        raise SystemExit(f"No download_url in response: {json.dumps(data, indent=2)}")

    print(f"  Downloading from {download_url[:80]}...")
    video_resp = requests.get(download_url, timeout=300)
    video_resp.raise_for_status()

    os.makedirs(os.path.dirname(output_path) or ".", exist_ok=True)
    with open(output_path, "wb") as f:
        f.write(video_resp.content)

    print(f"OK: {len(video_resp.content)} bytes -> {output_path}")


def generate(
    prompt: str,
    output_path: str,
    model: str = "MiniMax-Hailuo-2.3",
    duration: int = 6,
    resolution: str = "768P",

View on GitHub (pinned to 60aaae52bb)

Solutions

  1. Inspect the dumped JSON for the actual file object shape.
  2. Re-retrieve shortly — download_url may need propagation time after Success.
  3. Re-query video_generation to get a fresh file_id if the old one expired.

Example fix

# before
download_video(file_id, out_path)  # SystemExit: No download_url

# after - tolerate propagation lag
for _ in range(3):
    try:
        download_video(file_id, out_path); break
    except SystemExit as e:
        if 'download_url' in str(e):
            time.sleep(5); continue
        raise
Defensive patterns

Strategy: validation

Validate before calling

def has_download_url(resp_json: dict) -> bool:
    return bool(resp_json.get('file', {}).get('download_url'))
# after files/retrieve, before downloading:
if not has_download_url(data):
    raise RuntimeError(f'no download_url: {data}')

Type guard

def is_retrievable(d) -> bool:
    f = d.get('file') if isinstance(d, dict) else None
    return isinstance(f, dict) and isinstance(f.get('download_url'), str) and bool(f['download_url'])

Try / catch

try:
    download_video(file_id, out_path)
except SystemExit as e:
    if 'download_url' in str(e):
        time.sleep(5); download_video(file_id, out_path)
    else:
        raise

Prevention

When it happens

Trigger: files/retrieve returns a file object without download_url — file_id stale, file retention expired, propagation delay after Success, or response contract drift.

Common situations: Long delay between poll success and download; file_id from an old/reused task; file expired past MiniMax retention; API contract changed the nested key path.

Related errors


AI-assisted analysis of MiniMax-AI/skills@60aaae52bb (2026-08-13). Data as JSON: /api/errors/fb28104941859fc6. Report an issue: GitHub.