video_inspect 400s: frames at[] vs fps, and transcribe fields

Three video_inspect refusals: frames with both at[] and fps, frames with neither, and language_code without transcribe. Causes, fixes, a Python lint.

4 min readSume
All posts

POST /v1/video-inspect accepts one frames program per call: frames: { at: [...] } for explicit seconds, or frames: { fps: n } for a sampling rate. Sending both gives video_inspect_frames_program_conflict, sending an object with neither gives video_inspect_frames_program_required, and language_code, segmentation or duration_seconds without transcribe: true gives video_inspect_transcribe_required.

What does each refusal mean?

These codes come from the Video inspect page. An omitted frames means 8 mid-bin stills, frames: false means probe only, and an object must pass exactly one of at[] (1 to 24 values, each 0 or more) or fps (above 0, up to 2, capped at 24 stills). The speech-to-text fields only make sense when a transcript is requested, so they are refused on their own instead of ignored.

video_inspect request refusals, read 2026-10-03 from the Video inspect page
CodeRequestFix
video_inspect_frames_program_conflictframes has both at[] and fpsKeep one
video_inspect_frames_program_requiredframes is an object with neitherAdd at[] or fps, or use frames: false
video_inspect_transcribe_requiredlanguage_code, segmentation or duration_seconds without transcribeAdd transcribe: true, or remove the fields
inspect_source_has_no_audiotranscribe: true on a silent clipProbe with frames: false and read probe.has_audio first

How does this map to ffprobe and FFmpeg frame grabs?

With ffprobe you ask for stream facts, and with ffmpeg -vf fps=... you ask for stills in a separate command. Inspect folds both into one hosted call: the probe is always returned, and the stills follow the program above, with max_edge from 64 to 2160 (default 768) and a seek of precise or fast.

If you need source-size frames at known instants, the Video frames page is the other route: it takes at[] or fps too, with max_edge from 16 and no default clamp.

A lint you can run

The function below mirrors the three request-shape rules, so a client can reject a bad body before it spends a round trip. It runs as written.

Inspect defaults to mode: sync and waits up to 30 seconds for a 200, or answers 202 to poll. A transcript adds $0.01 per audio minute to the reservation, and omitting duration_seconds reserves 1 minute; the page says to confirm rates in GET /v1/catalog.

def inspect_error(body):
    f = body.get("frames")
    if isinstance(f, dict):
        if "at" in f and "fps" in f:
            return "video_inspect_frames_program_conflict"
        if "at" not in f and "fps" not in f:
            return "video_inspect_frames_program_required"
    if not body.get("transcribe") and any(
            k in body for k in ("language_code", "segmentation", "duration_seconds")):
        return "video_inspect_transcribe_required"
    return None

url = "https://media.sume.com/artifacts/artf_demo/talk.mp4"
print(inspect_error({"video_url": url, "frames": {"at": [1], "fps": 1}}))
print(inspect_error({"video_url": url, "frames": {}}))
print(inspect_error({"video_url": url, "language_code": "en"}))
print(inspect_error({"video_url": url, "frames": {"fps": 0.5}}))

Which program should I pick?

Use at[] when you know the moments that matter, for example the first frame of each scene, and fps when you want an even sample. With fps the output is capped at 24 stills, so a 60 s clip at 2 fps is truncated, and a lower rate gives better coverage of a long clip.

For a quick health check of a file, send frames: false and read the probe. It is the lightest call and tells you the duration, size and whether audio exists before you decide on stills or a transcript.

What does a valid request look like?

A probe-only request is { "video_url": ..., "frames": false }. A stills request is { "video_url": ..., "frames": { "at": [0, 2.5, 5] } }. A transcript request adds "transcribe": true, and only then may language_code appear. Everything else is a refusal at submit.

Since the rules are all about the shape of the body, they are easy to enforce in a typed client. Model frames as a union of three variants, and the three codes above become compile-time impossibilities.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume