ffmpegdockervideo-encoding

Unknown encoder 'libx264' isn't a bug. It's your FFmpeg build

·Javid Jamae·10 min read
Unknown encoder 'libx264' isn't a bug. It's your FFmpeg build

Your Dockerfile built clean. The ffmpeg command is copied from a machine where it works. The container still exits with Unknown encoder 'libx264' before it writes a single frame.

Quick answer: FFmpeg's "Unknown encoder 'libx264'" error means the ffmpeg binary you're running was compiled without --enable-gpl --enable-libx264, not that your command is wrong or that FFmpeg is broken. Run ffmpeg -encoders | grep 264 to see which H.264 encoders your build actually contains, then install a GPL-enabled build (Alpine's apk add ffmpeg, Debian's apt-get install ffmpeg, or a pinned static release) or fall back to -c:v libopenh264 -b:v 2M. If you'd rather not audit an encoder table on every deploy, send the job to FFmpeg Micro instead: one API call, no binary to install and no configure flags to get right.

The error is a build report, not a bug

Conventional wisdom says this error means something is wrong with your FFmpeg install, so people reinstall it. That's half right: something is wrong with the install, but reinstalling the same package gets you the same binary. FFmpeg prints Unknown encoder 'libx264' when it looks up the string you passed to -c:v in its encoder table and finds nothing. The table is fixed at compile time. If whoever built your binary didn't pass --enable-gpl --enable-libx264 to ./configure, x264 was never linked in and no amount of apt-get install --reinstall will conjure it.

One command tells you which side you're on:

ffmpeg -hide_banner -encoders | grep 264

A build with x264 answers like this:

 V....D libx264              libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)
 V....D libx264rgb           libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 RGB (codec h264)
 V....D h264_vaapi           H.264/AVC (VAAPI) (codec h264)

A build without it answers like this, and the absence of the libx264 line is your whole diagnosis:

 V....D libopenh264          OpenH264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)
 V....D h264_v4l2m2m         V4L2 mem2mem H.264 encoder wrapper (codec h264)

For the full picture, ffmpeg -buildconf prints every configure flag the binary was compiled with. Grep it for --enable-libx264. If it isn't there, stop debugging your command.

This question has been recurring for over a decade with the same answer every time: the ffmpeg-user mailing list fielded it in 2013, LinuxQuestions has a [SOLVED] thread on it, and the mobile builds have their own long-running versions in arthenica/ffmpeg-kit issue #1159 and tanersener/mobile-ffmpeg issue #127. Nobody's binary was corrupt. Every one of them had the wrong package variant.

libx264, h264, libopenh264, and h264_nvenc are four different things

Those four names get used interchangeably in tutorials, and mixing them up is how people end up debugging the wrong layer. h264 is the codec, the standard itself. libx264 is one software encoder that produces H.264, the GPL-licensed x264 library. libopenh264 is a different software encoder for the same codec, Cisco's implementation, shipped under a license distros are more comfortable with. h264_nvenc, h264_qsv, h264_vaapi, h264_videotoolbox, and h264_amf are hardware encoders that hand the work to a GPU or a fixed-function block.

There's a portable trick here. -c:v h264 asks FFmpeg for the codec rather than a named encoder, and FFmpeg resolves it to whichever H.264 encoder the build has, preferring libx264 when present. Run with -v verbose and you'll see it log Matched encoder 'libx264' for codec name 'h264'. For a script that has to run on machines you don't control, -c:v h264 survives builds that -c:v libx264 dies on.

The catch is that the encoders aren't interchangeable in their options. libopenh264 has no -crf, so every quality flag you copied from an x264 tutorial fails silently or errors out, and you have to switch to target bitrate with -b:v 2M. It also produces visibly worse output at the same bitrate on hard content. If your pipeline was tuned around constant quality, read when two-pass actually beats CRF before you pick a bitrate at random.

Which images and packages ship libx264 and which don't

Most mainstream Linux packages do include x264, which is exactly why the failures feel random: the images that don't ship it are the minimal, hardened, or license-cautious ones people move to for good reasons. Here's where the line falls.

Base image or packagelibx264 presentWhat's actually going on
`alpine:3.20` + `apk add ffmpeg`YesAlpine's community package is built with `--enable-gpl --enable-libx264`
`debian:bookworm-slim`, `ubuntu:24.04` + `apt-get install ffmpeg`YesDebian and Ubuntu ship the GPL build
`python:3.12-slim`, `node:22-slim` + apt installYesDebian-based, same package
Fedora / RHEL 9 `dnf install ffmpeg-free`NoPatent-encumbered encoders stripped; you get libopenh264 and hardware encoders only
conda-forge `ffmpeg` (default resolve)Noconda-forge publishes both lgpl and gpl build variants; the default lands on lgpl
`gcr.io/distroless/*`, `FROM scratch`NoNo package manager, nothing to install into
Recent official n8n imagesNoThe image went distroless in 2026, so `apk add ffmpeg` fails outright
ffmpeg-kit / mobile-ffmpeg `min`, `https`, `video`, `full`Nox264 is GPL, so only the `-gpl` package variants carry it
AWS Lambda AL2023 baseNo FFmpeg at allYou bring a layer or a static binary
johnvansickle and BtbN static release buildsYesGPL builds, x264 included

The n8n one bites hardest because every published "install ffmpeg in n8n" answer predates the change. The old USER root; RUN apk add --no-cache ffmpeg recipe just fails now. The community workaround is a multi-stage build that copies Alpine's apk and libapk.so* into the distroless base, which has to be re-verified on every n8n release.

Rebuilding FFmpeg from source is the wrong fix in a deploy pipeline

The top answer on most forums is to compile FFmpeg yourself with --enable-gpl --enable-libx264. That works on your laptop and it's a bad trade in a build pipeline. Compiling FFmpeg with x264, lame, and freetype runs roughly 10 to 20 minutes on a 4-vCPU CI runner, pulls nasm, pkg-config, and a C toolchain into your image, and hands you ongoing responsibility for tracking CVEs in FFmpeg and x264 yourself. There's a licensing consequence too: linking libx264 makes the resulting binary GPL, which is precisely why Fedora and conda-forge ship openh264 by default instead.

Pin a static build instead. Download a specific versioned artifact from johnvansickle.com or the BtbN/FFmpeg-Builds releases, verify its checksum, and copy it into the image. Never curl a URL that means "latest," because that's a silent version bump on a random Tuesday.

Then assert the encoder exists at build time rather than discovering it in production:

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg \
 && rm -rf /var/lib/apt/lists/*
RUN ffmpeg -hide_banner -encoders | grep -q '^ V.*libx264 ' \
 || (echo "FATAL: this ffmpeg has no libx264" && exit 1)

That single RUN line converts a runtime failure on a customer's upload into a red build. It costs nothing and it's the highest-value line in the Dockerfile.

There's a third option, which is to stop shipping an encoder at all. FFmpeg Micro is a managed FFmpeg build behind a REST API: you POST the job, poll or take a webhook, and download the output, with no binary in your image and no encoder table to audit. It's the same reasoning behind running video work outside Firebase Cloud Functions, and it works the same way from n8n, Make, Zapier, or an MCP tool call. The free tier is enough to test whether your job encodes correctly before you decide.

Common pitfalls that produce the same error

Once you know the build is the cause, a handful of specific mistakes account for most remaining cases.

  1. Two ffmpeg binaries on the box. You compiled to /usr/local/bin/ffmpeg but the shell cached the old /usr/bin/ffmpeg. Run which -a ffmpeg and hash -r, and in a container check that your entrypoint isn't using an absolute path to the wrong one.
  2. Picking the non-GPL mobile package. In ffmpeg-kit and mobile-ffmpeg, full does not include x264. Only the -gpl variants do. That single suffix is the entire content of both long-running issue threads.
  3. Assuming h264_nvenc in the encoder list means NVENC works. The encoder is compiled in; it still fails at runtime without the NVIDIA Container Toolkit and a mapped GPU. That failure reads Cannot load libnvidia-encode.so.1, which is a driver problem, not a build problem.
  4. Configure not finding x264 even though you installed it. ./configure --enable-gpl --enable-libx264 needs x264.pc on the pkg-config path, which usually means the -dev or -devel package, not just the runtime library. Check config.log for the failed pkg-config probe.
  5. Passing the codec name with stray whitespace. Template interpolation in n8n, Make, or a Node spawn call can hand FFmpeg libx264 with a trailing space, and the lookup fails on a string that looks correct in your logs.

If your pipeline is accumulating this kind of input-shaped failure, the same discipline applies to moov atom not found and height not divisible by 2: validate at the boundary, fail loudly, and don't let a class of error reach the encode step.

FAQ

Does apt install ffmpeg include libx264?

Debian and Ubuntu's ffmpeg package includes libx264, so apt-get install ffmpeg on debian:bookworm-slim, ubuntu:24.04, or any Debian-derived image like python:3.12-slim gives you a working -c:v libx264. Red Hat and Fedora are the exception: their ffmpeg-free package strips x264, and you need the RPM Fusion build or a static binary instead.

Can I use -c:v h264 instead of -c:v libx264?

-c:v h264 works and is more portable than -c:v libx264 because FFmpeg resolves the codec name to whatever H.264 encoder the build contains, preferring libx264 when it's present. The trade-off is that you no longer know which encoder you got, so options like -crf and -preset may not apply if the build resolves to libopenh264.

Is libopenh264 a real replacement for libx264?

libopenh264 encodes valid H.264 that plays everywhere, but it isn't a drop-in swap for libx264. It has no CRF mode, so you control quality with -b:v instead, and at matched bitrates it loses detail on high-motion footage that x264 holds. Use it when license constraints force your hand, not when you have a choice.

Why doesn't my self-compiled FFmpeg have libx264 when x264 is installed?

FFmpeg's configure script only links x264 when you explicitly pass both --enable-gpl and --enable-libx264 and pkg-config can find x264.pc. Installing the x264 runtime library alone isn't enough; you need the development package that ships the headers and the pkg-config file, and config.log will show the probe that failed.

How do I check FFmpeg's encoders without running a job?

Run ffmpeg -hide_banner -encoders | grep 264 to list every H.264 encoder in the binary, or ffmpeg -h encoder=libx264 to query one directly. A build without x264 answers the second command with Codec 'libx264' is not recognized by FFmpeg, which is the same diagnosis in one line.

Auditing encoder tables across four base images is work that produces no video. If you'd rather have H.264 output be a request instead of a build artifact, sign up free and run your first encode against a build that's already configured.

About Javid Jamae

Founder & CEO at FFmpeg Micro

Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.

Software EngineeringVideo ProcessingFFmpegCloud ArchitectureAPI DesignAutomation

Ready to process videos at scale?

Start using FFmpeg Micro's simple API today. No infrastructure required.

Get Started Free