video-filter invalid_filtergraph: every reason and the fix for each

A video-filter filtergraph is refused for eight reasons, from a [0:v] label to a quote character. What each one means and how to rewrite the graph so it passes.

5 min readSume
All posts

invalid_filtergraph on Sume video filter means the filtergraph string failed the contract check before any encoder started. The check is a pure string check, so you can reproduce it for free with POST /v1/video-filter/check, which returns diagnostics instead of a 400. The reason is one of eight, and the fix is almost always to delete something you copied from an ffmpeg command line.

The eight reasons

The server wraps your graph itself as [0:v] ... [vout], so the string you send is filters only. The validator in packages/timeline-compiler/src/filter.ts reports these reasons. The table pairs each with a typical cause.

Filtergraph validator reasons and limits, from the Sume docs and compiler source (read 2026-10-07)
ReasonWhat trips itFix
emptyBlank or whitespace-only stringSend at least one filter, or use ops[] instead
too_longMore than 2048 charactersMove crop and dim into ops[], shorten expressions
too_many_filtersMore than 32 named filtersSplit the work across two jobs
forbidden_token://, a backslash, backtick, $, double quote, &, newline or tab; or whitespace inside one filterUse single quotes only, write options as name=key=value:key=value with no spaces
input_referenceGraph starts with [, or a label is [0:v], [1:a] or a bare indexDrop the input label; the server supplies it
output_labelGraph ends with ]Drop [out]; the server maps the last filter
unbalancedUnclosed parenthesis or quoteCount them; commas inside (...) or '...' are protected
unknown_filterA name that is not on the allowlist, or text that is not a filter tokenCheck the allowlist below

Three rewrites that come up most

Pasting a full ffmpeg command is the first. A string such as -vf scale=1080:1920 -y out.mp4 fails because -vf is not a filter token, and the API rejects vf, filter, ffmpeg, cmd and codec as request fields as well (ffmpeg_fields_rejected). Send only scale=1080:1920.

Labels are the second. [0:v]scale=1080:1920[vout] fails twice, on the leading specifier and on the trailing output label. Internal labels such as [a] and [b] are fine inside split, overlay and hstack chains, because those need them to route one clip to two branches. Anything that starts with a digit or contains a colon is treated as a stream specifier.

Filter names are the third. drawtext, subtitles, movie and lut3d are not on the allowlist, since they read files or fonts. For burned-in text use video captions with cues. trim and setpts left the list when video trim shipped, so cut ranges with video trim.

What is on the allowlist

The docs describe the list as tone, blur, geometry, fade and internal compositing filters, and the source names them. Geometry includes crop, scale, pad, hflip, vflip, transpose, rotate, setsar, setdar, zoompan; time includes fps, tpad, fade, framerate, tblend, tmix; compositing includes split, overlay, hstack, vstack, blend, drawbox, drawgrid, format. The unknown-filter message prints the full list, so one failed check gives you the current one.

Check, then submit

Run the same body against the check route. A valid graph returns valid: true, encode: "not_run", the compiled filter names and an estimate. An invalid one returns diagnostics with the offending token. Encode jobs are $0.02 each and the check is free; confirm the live rate in GET /v1/catalog. A graph that passes can still fail on the box for a bad expression or memory, which comes back as a structured job error.

curl -X POST https://api.sume.com/v1/video-filter/check \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://media.sume.com/artifacts/artf_demo/talk.mp4",
    "filtergraph": "scale=1080:1920,eq=contrast=1.05"
  }'

Sources

Related posts

More in Media tools

All Media tools posts

Written by Sume