FFmpeg's error messages are precise but terse, and the useful line is rarely the last one printed. This is a lookup: the message you saw, what it actually means, and the fix. Where a message has several causes, they are ordered by how often each one is the real problem.
Read the right line
FFmpeg prints its build configuration before it does anything, so a failing command produces a wall of text where the error is a single line somewhere in it. Send the noise away and keep the errors:
ffmpeg -hide_banner -loglevel error -i input.mp4 output.mp4
When a command fails mysteriously and you need more rather than less, go the other way:
ffmpeg -loglevel debug -i input.mp4 output.mp4 2> ffmpeg-debug.log
And before debugging a command, check the file itself:
ffprobe -hide_banner input.mp4
That prints the container, the streams and the codecs. A surprising share of FFmpeg problems are a file that is not what someone assumed it was.
Unknown encoder 'libx264'
The FFmpeg binary was built without that encoder. This is not a syntax error and no change to your command will fix it.
Check what your build actually supports:
ffmpeg -encoders | grep 264 ffmpeg -codecs | grep 265
Distribution packages vary considerably in what they include, and minimal builds routinely omit x264 and x265 for licensing reasons. The fix is a build that includes them, or compiling with the encoder enabled.
The same message appears for h264_nvenc and h264_qsv when the hardware is not present or not exposed to the server: there the encoder exists in the build but cannot initialise.
No such file or directory
Usually a path problem in place of a missing file. Check the working directory, and quote paths containing spaces:
ffmpeg -i "/home/user/my videos/input.mp4" output.mp4
If it names the output instead of the input, the destination directory does not exist. FFmpeg does not create directories.
In a cron job this appears constantly, because cron does not start in your site directory. Use absolute paths for input, output and the FFmpeg binary itself. Setting up cron jobs in cPanel goes into it.
Invalid data found when processing input
FFmpeg could not make sense of the file. Three causes, in order.
The file is incomplete; an upload or download that stopped partway. Check the size against what it should be.
The file is not what its extension claims. ffprobe reports what it actually is.
The file is genuinely corrupt. Sometimes recoverable:
ffmpeg -err_detect ignore_err -i broken.mp4 -c copy fixed.mp4
That tells FFmpeg to continue past errors rather than stopping. The output may have glitches, and it is often the difference between a partly usable file and nothing.
Height/width not divisible by 2
H.264 requires even dimensions, and a scale filter preserving aspect ratio can produce an odd number.
# Wrong: -1 can give an odd height -vf scale=1280:-1 # Right: -2 rounds to an even number -vf scale=1280:-2
Use -2 everywhere by habit. There is no case where -1 is better and it fails unpredictably depending on the source aspect ratio.
Could not write header (incorrect codec parameters)
The container cannot hold the codec you asked for. MP4 does not accept every codec; putting Vorbis audio or an unusual video codec into MP4 produces this.
Either encode to something the container supports, or use a container that accepts it:
# Re-encode audio to something MP4 accepts ffmpeg -i input.mkv -c:v copy -c:a aac output.mp4 # Or keep everything and use MKV ffmpeg -i input.mkv -c copy output.mkv
This is the most common failure when stream copying between containers, because copying keeps codecs the destination may not allow.
Output file is empty, nothing was encoded
FFmpeg ran and produced nothing. Usually a filter or mapping excluded everything, or a seek landed past the end of the file.
Check that your -ss value is actually within the duration, and that any -map options refer to streams that exist. ffprobe lists them with their indexes.
Killed, with no FFmpeg error at all
The process ran out of memory and the operating system terminated it. FFmpeg did not fail; it was stopped.
This is common on shared or small instances with 4K sources, complex filter chains, or several jobs at once. Reduce what is in flight: scale down before filtering, process one file at a time, or split long inputs into segments.
If it happens routinely on ordinary work, the environment is too small for the workload in place of the command being wrong.
Permission denied
Check that the output directory is writable by the user running FFmpeg. Under cron that user may not be the one you tested as.
Never resolve this by setting a directory to 777. It makes the directory writable by anyone on the server, and the correct fix is ownership.
Works in the shell, fails from cron or PHP
Almost never an FFmpeg problem. Cron and PHP run with a different working directory, a minimal PATH, and none of your shell profile.
Use the full path to the binary:
/usr/bin/ffmpeg -i /home/user/in.mp4 /home/user/out.mp4
Find it with which ffmpeg. And capture stderr, or you will get a silent failure with nothing to read:
/usr/bin/ffmpeg -i in.mp4 out.mp4 >> /home/user/ffmpeg.log 2>&1
From PHP, the same applies plus one more: the web server user usually has a restricted environment and may not be permitted to execute binaries at all.
Conversion failed, with no clear reason
Reduce the command until it works. Remove filters, then options, until you reach something that succeeds, then add pieces back one at a time.
A plain stream copy is the useful floor:
ffmpeg -i input.mp4 -c copy test.mp4
If that fails, the problem is the input or the environment. If it succeeds, the problem is in what you were asking FFmpeg to do, and adding options back one at a time will find it in a couple of minutes.
Comb-like lines during motion are not an encoding fault at all but interlaced source. How to Deinterlace and Change Frame Rate with FFmpeg deals with confirming and converting it.
A conversion that changes how the picture looks is not an encoder fault at all. For the two causes, see Why Converted Video Looks Washed Out or Too Dark.