ffmpegvideo-encodingtroubleshooting

Fix FFmpeg's "height not divisible by 2" Error on User Uploads

·Javid Jamae·10 min read
Fix FFmpeg's "height not divisible by 2" Error on User Uploads

A user uploads a screen recording. Your pipeline scales it to 720p, hands the frames to libx264, and the job dies before it writes a single frame: height not divisible by 2 (720x959). Nothing is wrong with the file, and nothing is wrong with your command except one missing rounding rule.

Quick answer: The FFmpeg error "height not divisible by 2" comes from libx264 encoding to the yuv420p pixel format, which stores chroma at half resolution and therefore needs both output dimensions to be even. Fix it in the filter chain with scale=-2:720 when you're preserving aspect ratio, crop=trunc(iw/2)*2:trunc(ih/2)*2 when you'll accept losing one row or column, or pad=ceil(iw/2)*2:ceil(ih/2)*2 when you can't lose a pixel. If you'd rather not carry that rule into every job you write, FFmpeg Micro's hosted resize endpoint rounds output dimensions to even numbers by default, so arbitrary phone and screen-recording uploads never fail encoder init.

Why yuv420p forces even width and height

The constraint lives in the pixel format, not in FFmpeg and not in your file. In yuv420p, the two chroma planes are subsampled by two in both directions, so a 720x959 luma plane would need a 360x479.5 chroma plane. There's no such thing as half a chroma sample, so libx264 refuses the frame size rather than emit a stream nobody can decode.

The H.264 spec backs it up. Coded frames are made of 16x16 macroblocks, and the cropping offsets that trim a coded frame down to its display size are counted in chroma samples for 4:2:0 content. Those offsets are always multiples of two, which means an odd display height is literally unrepresentable in a 4:2:0 H.264 stream.

On FFmpeg 7.x the failure prints:

[libx264 @ 0x7f9e1c008200] height not divisible by 2 (720x959)
[vost#0:0/libx264 @ 0x7f9e1c007a80] Error while opening encoder - maybe incorrect
parameters such as bit_rate, rate, width or height.
Error while filtering: Generic error in an external library

On FFmpeg 4.x and 5.x the same thing prints as Error initializing output stream 0:0 -- Error while opening encoder for output stream #0:0. Either way it's an encoder initialization failure, which matters for pipeline design: the job dies at second zero, after you've paid to fetch the source and before you've produced anything. It fails fast, but it fails on every affected upload forever, because the cause is the source dimensions and those don't change on retry.

The three fixes and when each one is right

There are three ways to force even dimensions, and they trade off differently: one resamples, one throws a pixel away, one adds a pixel. Measured on a 1470x945 window capture, the difference is small but not invisible.

FilterOutputWhat it costs
`scale=-2:720`1120x720Full resample. Aspect held at 1.5556
`crop=trunc(iw/2)*2:trunc(ih/2)*2`1470x944Bottom row dropped. Aspect drifts to 1.5572
`scale=trunc(iw/2)*2:trunc(ih/2)*2`1470x944Same size as the crop, but the whole image is resampled
`pad=ceil(iw/2)*2:ceil(ih/2)*2`1470x946One black row added at the bottom

scale=-2 is the default when you're already resizing

Use scale=-2:720 (or scale=1080:-2) any time you're resizing and want the aspect ratio preserved. The negative value tells FFmpeg to compute that dimension from the other one and round it to a multiple of two.

ffmpeg -i upload.mp4 -vf "scale=-2:720" -c:v libx264 -pix_fmt yuv420p out.mp4

The trap is -1, which does the same aspect math with no rounding rule at all. On a 1080x1439 phone screen recording, scale=720:-1 computes 959.33 and hands libx264 a 720x959 frame. scale=720:-2 computes the same number and rounds to 960. One character.

crop or trunc when you'll accept losing a pixel

Reach for truncation when the output size is dictated by the source and you're not resizing. trunc(iw/2)*2 rounds each dimension down to the nearest even number, so 945 becomes 944.

ffmpeg -i upload.mp4 -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" \
  -c:v libx264 -pix_fmt yuv420p out.mp4

Most guides write this with scale instead of crop, and it works, but it resamples all 1.4 million pixels to shave one row. crop drops the row and leaves every remaining pixel bit-identical, which matters for screen recordings where text sharpness is the whole point. Use scale=trunc(iw/2)*2:trunc(ih/2)*2 only when a scale filter is already in the chain for other reasons.

pad when you can't lose a pixel

Padding is right when the frame content is fixed and cropping would clip something you need, like a slide deck, a product shot framed to the edge, or a chart with an axis label on the last row.

ffmpeg -i upload.mp4 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2,setsar=1" \
  -c:v libx264 -pix_fmt yuv420p out.mp4

ceil rounds up, so 945 becomes 946 and the new row is filled with black by default. On a light-background screen recording that single black line reads as a visible seam along the bottom edge, so pass a matching fill: pad=ceil(iw/2)*2:ceil(ih/2)*2:0:0:color=white. The setsar=1 matters too, because a padded frame that inherits a non-square sample aspect ratio from an anamorphic source will get stretched by the player.

Which codecs actually impose the constraint

The rule follows chroma subsampling, which is why the same odd-dimension source encodes fine to some targets and fails on others. This is what confuses people who test with a ProRes intermediate and hit the error only in production.

Encoder and pixel formatEven widthEven height
libx264 / libx265, yuv420pRequiredRequired
libx264, yuv422pRequiredNot required
libx264, yuv444pNot requiredNot required
ProRes (422 family)RequiredNot required
MJPEG in AVI, yuvj444pNot requiredNot required
h264_nvenc and other hardware encodersRequiredRequired
libvpx-vp9, yuv420pNot requiredNot required

ProRes 422 subsamples chroma horizontally only, so an odd height is fine and an odd width still isn't. MJPEG at 4:4:4 doesn't subsample at all, which is why an old AVI workflow will happily swallow 1470x945 and an MP4 workflow won't. VP9 and AV1 define odd frames by rounding the chroma plane size up with (w+1)>>1, so the same source can produce a working WebM and a failed MP4 in the same run.

Hardware encoders are stricter, not looser. Arbitrary input resolutions come up repeatedly on NVIDIA's developer forums, and the answer is the same: round before the frame reaches the encoder, because NVENC won't do it for you.

One thing not to do: switching -pix_fmt yuv420p to yuv444p makes the error disappear and breaks playback nearly everywhere. 4:4:4 H.264 requires the High 4:4:4 Predictive profile, which QuickTime, Safari, and most browser <video> implementations won't decode. You'll trade a loud build-time failure for a silent black player on half your users' devices.

Where odd dimensions come from in an upload pipeline

If you control your inputs, you'll never see this error. If you accept uploads, you'll see it within the first few hundred jobs, and always from one of four places.

Ratio scaling is the most common. scale=iw/3:ih/3 on a 1280x720 clip computes 426.67x240, FFmpeg rounds the width to 427, and libx264 rejects it with the width version of the same message. Any divisor that isn't a clean factor of both dimensions will do this eventually.

Aspect-ratio cropping is next. Cutting a 1080-pixel-wide vertical video to 16:9 needs a height of 607.5, and whichever way you round, half the time you land on an odd number. Face-box and subject-detection crops are worse, because the box comes from a model and has no reason to be even at all.

Then there's arbitrary source footage. Phone video is almost always even, but window captures, cropped exports out of an editor, GIF conversions, and anything that's been through a resize in a browser are not. Screen recordings of a scaled display are a reliable source of odd heights.

Encoding that rule into every command works right up until you have a dozen commands. If the video step is one part of a larger workflow, normalizing dimensions once at the boundary is cheaper: FFmpeg Micro runs FFmpeg as a hosted API and its resize enforces even output dimensions by default, so an odd-height upload comes back as a playable MP4 instead of an encoder error you have to catch and retry. You can throw a deliberately odd-dimension file at it in the playground before wiring anything up.

Common pitfalls

The rounding filter has to be the last video filter in the chain. Put scale=-2:720 before a crop and the crop reintroduces an odd dimension downstream, and the error you get back names dimensions that appear nowhere in your command.

Keep your crop offsets even too. crop=w:h:x:y with an odd x or y shifts the luma plane by one pixel while chroma can only move in steps of two, which produces a faint color fringe on high-contrast edges. Wrap them the same way: crop=trunc(iw/2)*2:trunc(ih/2)*2:trunc(x/2)*2:trunc(y/2)*2.

When you're normalizing many sources to one canvas, don't stack rounding filters. Use the built-in combination instead, which handles both the fit and the even-dimension requirement in one pass because 1080 and 1920 are already even:

ffmpeg -i upload.mp4 -vf "scale=1080:1920:force_original_aspect_ratio=decrease,\
pad=1080:1920:(ow-iw)/2:(oh-ih)/2,setsar=1" -c:v libx264 -pix_fmt yuv420p out.mp4

This is also the fix for the stacking filters, which are pickier than the encoder: hstack needs identical heights and pixel formats across inputs and vstack needs identical widths, so normalize first as covered in putting two videos side by side. The same normalize-first habit is what keeps a batch transcode across a folder from dying on file 340 of 500.

Last one: -vf and -filter_complex don't combine. If you're already using -filter_complex for an overlay or a concat, the rounding has to go inside it, appended to the final filter's output chain, not tacked on as a separate -vf.

FAQ

Why does FFmpeg say height not divisible by 2 when my source video plays fine?

The error is about the output dimensions, not the input. Your source plays fine because whatever encoded it either used even dimensions or used a format without 4:2:0 chroma subsampling, and your FFmpeg command is producing an odd height on the way out, usually from a scale or crop expression that computed a fractional value.

What's the difference between scale=-1 and scale=-2 in FFmpeg?

scale=-1 tells FFmpeg to compute that dimension from the aspect ratio and use it as-is, odd numbers included. scale=-2 does the same math and rounds the result to a multiple of two, which is why -2 is the value to default to for any H.264 output.

Does the height not divisible by 2 error mean my file is corrupt?

No. The error is raised by libx264 during encoder initialization, before it touches your frames, purely on the basis of the requested output size. A corrupt input produces different errors entirely, like a missing moov atom or a decode failure partway through.

How do I make FFmpeg round dimensions to even numbers automatically?

FFmpeg won't round automatically, so you have to say so in the filter chain. Use scale=-2:<height> when resizing, or scale=trunc(iw/2)*2:trunc(ih/2)*2 when you want to keep the source size and just force it even.

Can I avoid the error by switching to yuv444p?

Switching to yuv444p removes the even-dimension requirement because 4:4:4 doesn't subsample chroma, but it forces the High 4:4:4 Predictive profile, which Safari, QuickTime, and most browser video players can't decode. Round the dimensions instead and keep yuv420p.

Normalizing dimensions is the kind of rule that's easy to write once and expensive to forget in job number seven. If you'd rather have it enforced at the boundary than re-derived in every command, sign up free and send an odd-height file through the resize endpoint to see what comes back.

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