# Common FFmpeg errors and what they mean

Canonical: https://rendobar.com/blog/ffmpeg-errors-explained/
Author: Abdelrahman Essawy
Published: 2026-08-20
Updated: 2026-08-20

---

## Key takeaways

- 208 of 1,978 jobs did not complete, a 10.5% failure rate. FFmpeg jobs specifically failed 129 times out of 1,306, or 9.9%.
- More jobs failed on an unreachable input (61) than on FFmpeg rejecting the command (45). The most common cause of a failed video job is not FFmpeg.
- One message accounts for 25 of the 37 FFmpeg-level errors: 'Invalid argument. Check your FFmpeg flags and values.' It almost never means what it says.
- Overlay is the worst offender. 21 of 40 overlay jobs failed, and 14 of those returned that same generic Invalid argument message.
- 5 failures were 'Error opening output files: Filter not found', which is a typo in a filter name and nothing to do with the output file.

## Short version

We went through every job in Rendobar's history that did not complete. **208 failures out of 1,978 jobs, a 10.5% failure rate**, and for FFmpeg jobs specifically **129 out of 1,306, or 9.9%**.

Then we grouped them by what actually went wrong. The result is not what people expect.

| What failed | Count |
|---|---|
| The input could not be downloaded | **61** |
| FFmpeg rejected the command | **45** |
| Something else, unclassified | 23 |
| No message was recorded | 19 |
| The job never reached a runner | 17 |
| An upstream provider failed | 10 |
| Something was too large | 9 |
| The output stage failed | 9 |
| An input reference was missing | 6 |
| Rejected before it ran | 6 |
| The input was not media | 3 |

**More jobs died on a URL than on a command.** Expired links, 401s, 404s and one origin returning 429 outnumbered FFmpeg's own complaints by 61 to 45. If you are debugging a pipeline that fails intermittently, check the input fetch before you touch the filter graph.

## The one message you will see most

Of the 37 failures that carried FFmpeg's own error text, **25 returned exactly this**:

```
Invalid argument. Check your FFmpeg flags and values.
```

That message is honest about being unhelpful. It almost never means a flag value is out of range. In every case we traced, it meant **the filter graph did not parse**.

The tell is the timing. All 25 failed at **0 seconds**. Nothing was decoded, nothing was encoded, no input was read. FFmpeg parsed the command line, could not build the graph, and stopped. A failure at 0 seconds is a syntax problem, so the input file, the codec and the encoder settings are all irrelevant to it.

## Overlay is the worst offender

**21 of 40 overlay jobs failed**, and **14 of those returned the generic Invalid argument message**. That is more than half the overlay attempts in the entire archive.

The reason is structural rather than careless. `overlay` takes **two** inputs. `-vf` only ever sees the first one. So this cannot work no matter how the coordinates are written:

```bash
# Fails. -vf has no access to the second input.
ffmpeg -i base.mp4 -i logo.png -vf "overlay=10:10" out.mp4
```

Two inputs means `-filter_complex` and explicit labels:

```bash
# Works.
ffmpeg -i base.mp4 -i logo.png \
  -filter_complex "[0:v][1:v]overlay=W-w-20:H-h-20" \
  -c:a copy out.mp4
```

`[0:v]` is the video of the first input, `[1:v]` the video of the second. `W` and `H` are the base dimensions, `w` and `h` the overlay's, so `W-w-20` pins it 20 pixels from the right edge.

The rule generalises past overlay. **Any filter with more than one input needs `-filter_complex` and labels.** That covers `concat`, `amix`, `hstack`, `blend` and every transition.

## Filter not found points at the wrong place

Five failures returned this:

```
Error opening output files: Filter not found
```

The phrase "output files" sends people to check their output path and their container. The output is fine. **A filter name in the graph is misspelled, or is not compiled into the build you are running.**

FFmpeg builds genuinely differ. A filter that works on your laptop can be absent from a container image, and the message is the same either way. `ffmpeg -filters` lists what your build actually has, which settles it in one command.

The same applies to encoders, and we hit both. One job asked for `libfdk_aac`, which is not in most distributed builds because of its licence. Another asked for `libx264__nvec`, which is a typo. Both came back as the codec not being available, with a suggestion to use `libx264` instead.

## Failures that were never about FFmpeg

**61 of 208** could not download the input. The messages name the cause directly and they are worth reading as a category, because each has a different fix.

A **404** means the URL is wrong or the object is gone. A **401** means the URL needs credentials the fetch did not have, which is the usual outcome of passing a private storage link without signing it. A **429** means the origin rate-limited us, which happened when a job pulled an asset from a public wiki. A plain fetch failure means DNS or TLS.

Presigned URLs deserve their own warning. They expire. A URL that worked when you wrote the job and fails when you retry it three hours later is not an intermittent bug, it is a signature that timed out.

**9 failures were about size.** Payloads over the accepted limit, and one request for an output of 2730x4096, which is 11.2 megapixels, against a GPU that could hold 9.9. Those are limits, not errors, and they fail fast rather than half-rendering.

## Reading a failure in the right order

The distribution above suggests a debugging order that is not the instinctive one.

**First, did the job run at all.** If it failed at 0 seconds, stop looking at the media. It is a parse error. If it never started, it is infrastructure and retrying is reasonable.

**Second, did the input arrive.** This is the single largest category and it is invisible from the command. Fetch the URL yourself, unauthenticated, from somewhere other than your machine.

**Third, does the filter graph parse.** Build it up one filter at a time. Every label you reference must be one you defined, every multi-input filter needs `-filter_complex`, and every branch must be consumed.

**Fourth, does your build have the pieces.** `ffmpeg -filters` and `ffmpeg -encoders` answer this immediately and rule out an entire class of confusing messages.

Only after all four is it worth looking at flag values, which is where most people start.

## Running it where the error comes back structured

Rendobar's FFmpeg API returns the failure reason on the job rather than making you scrape stderr, and it records the stage at which the job died, so "the input never downloaded" and "FFmpeg rejected the command" are distinguishable without reading logs.

const rb = createClient({ apiKey: process.env.RENDOBAR_API_KEY });

// throwOnFailure:false returns the failed job instead of raising, so you can
// read WHICH stage died rather than scraping stderr.
const job = await rb.jobs.run(
  {
    type: "ffmpeg",
    params: { command: "ffmpeg -i https://example.com/missing.mp4 -c:v libx264 out.mp4" },
  },
  { throwOnFailure: false },
);

if (job.status === "failed") {
  // "could not fetch input" and "FFmpeg execution failed" are different
  // problems with different fixes. 61 of our 208 failures were the first.
  console.error(job.error.message);
}`}
  curl={`curl -X POST https://api.rendobar.com/jobs \
  -H "Authorization: Bearer $RENDOBAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ffmpeg",
    "params": { "command": "ffmpeg -i https://cdn.rendobar.com/assets/examples/sample.mp4 -i https://cdn.rendobar.com/assets/examples/photo.jpg -filter_complex \"[0:v][1:v]overlay=W-w-20:H-h-20\" -c:a copy -t 5 out.mp4" }
  }'`}
/>

Probing the input first is the cheapest way to remove the largest failure category. A probe bills a flat $0.0010 against a median FFmpeg job of $0.0025, and it answers "is this URL reachable and is it media" before you pay to encode.

## Where this stops

This is our traffic, not yours. It is heavily weighted toward testing and content production, which means an unusual concentration of deliberately broken commands and deliberately dead URLs. A production pipeline running one known-good command against reliable storage will not see a 10.5% failure rate, and the shape of its failures will differ.

**19 failures recorded no message at all and 23 more did not match any family**, so about a fifth of the sample is unclassified and could belong to any category above. The counts should be read as a ranking rather than as precise proportions.

We also cannot tell you FFmpeg's own stderr for most of these, because the API surfaces a normalised message rather than the raw output. That is a real limitation when the raw text would name the exact filter that failed.

For the input side specifically, see [validating video uploads with ffprobe](/blog/ffprobe-validate-uploads/), which covers using a probe as a gate. For what a job costs when it does work, see [FFmpeg API pricing compared](/blog/ffmpeg-api-pricing-compared/). For the settings themselves, see [FFmpeg encoding settings measured](/blog/ffmpeg-encoding-settings/).
