Lint a Video Router request offline: reference limits in Python

Check reference_image_urls (10), reference_video_urls (3), reference_audio_urls (1-5) and the video_url rule in Python before POST /v1/video-router/generate.

5 min readSume
All posts

A 400 from a submit is a wasted round trip, and a bad batch of fifty bodies is a wasted afternoon. Lint the body in Python first: count each reference list against the limits in the OpenAPI schema and refuse a Gemini Omni video_url edit source that rides with other media fields.

The linter checks shape only. Which reference types a particular model accepts still comes from its catalog entry.

Which limits does the lint check?

These are the limits in the Video Router request schema and docs (read 2026-10-09).

Video Router reference limits (Sume OpenAPI and docs, read 2026-10-09)
FieldLimitNotes
reference_image_urls1 to 10 when presentPublic HTTPS URLs
reference_video_urls1 to 5 in the schemagemini-omni-flash-1.1 accepts at most 3, each 3 seconds or less
reference_audio_urls1 to 5 when presentAn empty list is not valid
video_urlOne source clipFor gemini-omni-flash-1.1 edits it cannot be combined with image_url, end_image_url or reference_*_urls
wait_timeout_seconds0 to 30Blocking wait for sync or subscribe only

What is the function?

It returns a list of problems, so a batch run can print every bad body at once instead of stopping on the first.

def lint(body: dict) -> list[str]:
    bad = []
    caps = {"reference_image_urls": (1, 10),
            "reference_video_urls": (1, 5),
            "reference_audio_urls": (1, 5)}
    for field, (low, high) in caps.items():
        if field in body:
            n = len(body[field])
            if not low <= n <= high:
                bad.append(f"{field}: {n} entries, allowed {low}-{high}")
    if body.get("model") == "gemini-omni-flash-1.1":
        if len(body.get("reference_video_urls", [])) > 3:
            bad.append("Omni takes at most 3 reference videos")
        if "video_url" in body:
            clash = [f for f in body if f.startswith("reference_")
                     or f in ("image_url", "end_image_url")]
            if clash:
                bad.append(f"video_url cannot ride with {clash}")
    for field, urls in body.items():
        if field.endswith("_urls") or field.endswith("_url"):
            for u in urls if isinstance(urls, list) else [urls]:
                if isinstance(u, str) and not u.startswith("https://"):
                    bad.append(f"{field}: not https: {u}")
    w = body.get("wait_timeout_seconds")
    if w is not None and not 0 <= w <= 30:
        bad.append("wait_timeout_seconds must be 0-30")
    return bad
print(lint({"model": "gemini-omni-flash-1.1", "video_url": "https://a.co/a.mp4",
            "reference_image_urls": ["https://a.co/a.png"]}))

What stays out of the lint?

Clip length. A reference video of three seconds or less needs the file itself, and the catalog may allow fewer types for the model you chose. Fetch GET /v1/video-router/models/{id} for those. Other models can differ: h3-max-recast, for example, takes a video_url together with reference_image_urls, so the edit-source rule above is applied only to Omni. Do not copy the limits above into other docs, since a model entry can be stricter than the router.

Where should the lint run?

Run it in the step that builds the body, before the Idempotency-Key is assigned, so a rejected body never consumes a key. Log the whole list of problems with the item's index and then continue with the next item.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume