Reference video job failed on download: check input URLs first

A Sume reference-to-video job fails when an input URL is not public. Python that HEAD-checks references before POST /v1/videos, and how to read the error.

4 min readSume
All posts

If a Sume reference-to-video job fails with a message about not downloading an input media URL, the file was not publicly reachable when Sume fetched it. Check every URL with a HEAD request before you submit: it must be public HTTPS, return 200, and look like the media type you declared. A failed job with this error is terminal, so you fix the URL and submit a new job.

What the failure looks like

Sume does not return the raw provider wrapper. The poll response for a failed job carries a public remap of the error, and for an unreachable image or video reference it reads: Could not download an input media URL (image_url). Verify the URL is publicly reachable, then retry. The URL itself stays private in the response.

On a terminal failure the content route answers 409 job_failed, with retryable false, so do not wait on content. Read the error field of GET /v1/videos/{id} instead.

Think about who fetches the file. It is Sume's worker, not your laptop, so a URL that opens in your browser because you are logged in, or because it is on your VPN, can still fail. The only reliable test is an anonymous request from outside your network, which the HEAD check below approximates.

Which fields take URLs

The mode is inferred from which field you send. Frame images pin a first or last frame for image-to-video. Input references condition a reference-to-video clip. Both carry URLs that Sume fetches from its side, so a link behind a login, a signed URL that expires in a minute, or a private bucket fails the same way.

URL-bearing fields on POST /v1/videos (Sume docs, read 2026-10-05)
FieldModeAccepted typesNote
frame_imagesImage-to-videoimage_url with frame_typefirst_frame or last_frame
input_referencesReference-to-videoimage_url, video_url, audio_urlPer model, see supported_input_references
callback_urlWebhookHTTPS URLMust be public, not a URL you fetch
video_url on OmniEditVideo Router field onlySource clip, not in the OpenRouter-shaped body

A preflight check

The script sends a HEAD request to each reference, follows redirects, and fails fast on anything that is not a 200 with an image or video content type. HEAD is not perfect, since some servers reject it, so fall back to a ranged GET for those.

import urllib.request, urllib.error

def check(url: str, kinds=("image/", "video/")) -> str:
    if not url.startswith("https://"):
        return "not https"
    req = urllib.request.Request(url, method="HEAD", headers={"User-Agent": "preflight"})
    try:
        with urllib.request.urlopen(req, timeout=10) as r:
            ctype = r.headers.get("content-type", "")
            if r.status != 200:
                return f"status {r.status}"
            if not ctype.startswith(kinds):
                return f"content-type {ctype!r}"
            return "ok"
    except urllib.error.HTTPError as e:
        return f"http {e.code}"
    except Exception as e:
        return f"error {type(e).__name__}"

refs = ["https://www.sume.com/robots.txt", "http://example.com/a.png", "https://example.invalid/x.jpg"]
for u in refs:
    print(u, "->", check(u))

Why this saves real money

A job that fails before generation starts is refunded, since Sume releases the reservation on failures where it applies. You still lose the wait, and in a batch you lose the whole wave slot, because a bad URL sits in your queue for minutes before it fails. A 10-second check up front costs nothing.

Treat the check as one step in a longer preflight. Compare the model's supported_input_references with the types you are sending, because a reference type that one model accepts is a 400 unsupported_capability on another. Omni, for instance, accepts image and video references but not audio ones.

If you run many jobs against the same reference set, check each URL once and cache the answer for the run. A character sheet or a product photo reused across 50 clips needs one check, not 50, and one fix when it breaks.

Hosting tips

  • Use durable public HTTPS URLs, for example your own storage or CDN, not a short-lived signed link.
  • Keep inputs for as long as the job might run, which can be many minutes for a long clip.
  • If you retry the same intent after fixing the URL, change the Idempotency-Key, since the body changed.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume