FFmpeg "Buffer Queue Overflow, Dropping" Is a Timestamp Bug

Your render finishes, the exit code is 0, and the log has eight hundred copies of the same line. The output plays, mostly, except the watermark freezes halfway or the music drifts out of sync with the voiceover. That warning wasn't noise, it was FFmpeg telling you it threw frames away.
Quick answer: "Buffer queue overflow, dropping" is a libavfilter warning that appears when one input of a multi-input FFmpeg filter (overlay,amix,concat,hstack,xfade) keeps producing frames while another input has nothing to pair them with, so the queued frames exceed their bound and get discarded. Fix it at the source of the skew: putsetpts=PTS-STARTPTS(andasetpts=PTS-STARTPTS) after everytrim/atrim, drop-loop 1on still-image overlays, and setshortest=1onoverlayorduration=shortestonamixso the graph ends when the short input does. If you'd rather not hand-align durations for every job, send the inputs to FFmpeg Micro as one API call and let it probe and normalize them before the graph runs.
Why the warning is about time, not memory
Conventional wisdom says a buffer overflow means you need a bigger buffer. For this message, that's partly true and almost always the wrong move. The queue isn't full because it's too small, it's full because the two branches of your graph disagree about what time it is.
An FFmpeg filter graph is pull-based. A filter with two inputs can't emit anything until it has a frame from each at a matching presentation timestamp, which is what framesync inside overlay, amix, hstack and xfade does. If branch A hands over a frame stamped pts_time:600.0 and branch B is still at pts_time:0.4, the filter has to hold A's frame and wait. Then the next one. The queue in front of that input is bounded, and when it's exceeded libavfilter drops frames and logs the line.
The number of warnings roughly measures your skew. Two or three at the start of a run is an alignment hiccup. Hundreds mean one branch is minutes ahead of the other and will never be caught.
Ticket 5257 has been the canonical report on FFmpeg's own tracker for years, and it surfaces downstream in projects that only shell out to FFmpeg: 3D Slicer forum thread 17681 has users hitting it during animation export on Windows but not Linux. The drops are timing-dependent, which is why the same command can look clean on one machine and flood on another. No documentation page explains this, so most people meet it in a GitHub issue.
How to read which input is starving
The bracketed prefix in the warning names the filter instance whose input queue blew up, so you already know which join is stuck:
[Parsed_overlay_0 @ 0x55a3f0a1c640] Buffer queue overflow, dropping.
[Parsed_overlay_0 @ 0x55a3f0a1c640] Buffer queue overflow, dropping.
frame= 1800 fps=142 q=28.0 size= 11520KiB time=00:01:00.00 bitrate=1572.8kbits/s
From there, four checks find the culprit nearly every time.
- Read the filter name in brackets.
Parsed_overlay_0is the firstoverlayin your-filter_complex.Parsed_amix_2is the third filter and it's anamix. That's your starved node. - Probe every input for duration and start time.
ffprobe -v error -show_entries format=duration:stream=start_time,r_frame_rate,sample_rate -of json input.mp4on each file. Astart_timethat isn't near 0, or two durations that differ by minutes, is the answer. - Insert
showinfobefore the join. Add it to the end of each branch and compare the firstpts_timeeach one prints:-filter_complex "[0:v]trim=start=600:end=630,showinfo[a];[1:v]showinfo[b];[a][b]overlay". One branch starting atpts_time:600.0next to one starting atpts_time:0.0is the whole bug, visible in two log lines. - Grep your own command for infinite inputs.
-loop 1,-stream_loop -1, and-f lavfi -i "anullsrc"all produce input that never ends. An endless input paired with a finite one is the most common shape of this failure.
Reading the log closely pays off elsewhere too, like progress reporting, where the frame counter lies and `out_time_us` doesn't.
The graphs that produce it, and the actual fix
Three command shapes account for most of these reports, and each has a different fix.
| Symptom | Real cause | Fix |
|---|---|---|
| Warning floods immediately, watermark freezes | `-loop 1 -i logo.png` feeding `overlay` with no terminator | Drop `-loop 1`, or add `shortest=1` to `overlay` |
| Audio glitches or desyncs after a mix | `amix` inputs of different length, one much longer | `duration=shortest`, or `apad` the short one |
| Warning starts after a cut, output is a frozen frame | `trim`/`atrim` passes through source PTS | `setpts=PTS-STARTPTS` / `asetpts=PTS-STARTPTS` |
A looped PNG watermark
Stamping a logo does not need a looped input. overlay defaults to eof_action=repeat, which holds the last frame of the secondary input as long as the main input keeps going, so a single still image works on its own:
ffmpeg -i clip.mp4 -i logo.png \
-filter_complex "[0:v][1:v]overlay=W-w-20:H-h-20" \
-c:a copy out.mp4
If you genuinely need a looping animation, give it a frame rate and tell the join to end with the short input: -loop 1 -framerate 30 -i logo.png plus overlay=...:shortest=1. Without shortest=1, the looped source runs forever, the overlay queue fills, and you get the flood.
A music bed longer than the clip
amix with duration=longest (the default) keeps the mix running as long as the longest input, which means every frame of the short input's silence has to come from somewhere. State what you want instead:
ffmpeg -i voice.wav -i music.mp3 \
-filter_complex "[1:a]volume=0.2[m];[0:a][m]amix=inputs=2:duration=shortest[a]" \
-map "[a]" out.m4a
When the video is longer than the audio and you want the audio to stretch, apad is the right tool: -filter_complex "[0:a]apad[a]" -map 0:v -map "[a]" -shortest pads with silence to the video's length and stops there. Getting the mux right after the mix has its own traps, which we walked through for audio replacement.
A trim chain that breaks PTS continuity
A broken trim chain confuses people most, because the command looks correct. trim and select filter frames but pass their original timestamps straight through. Cut 30 seconds out of the ten-minute mark and your branch emits frames stamped at 600 seconds while everything else in the graph starts at zero. Rebase after every cut:
ffmpeg -i source.mp4 \
-filter_complex "[0:v]trim=start=600:end=630,setpts=PTS-STARTPTS[v0]; \
[0:a]atrim=start=600:end=630,asetpts=PTS-STARTPTS[a0]; \
[v0][1:v]overlay=10:10[v]" \
-map "[v]" -map "[a0]" out.mp4
Miss asetpts and you get the audio version of the same flood plus a silent output. The rule is mechanical: one setpts=PTS-STARTPTS per trim, one asetpts=PTS-STARTPTS per atrim, every time, even when it looks redundant.
When fifo is the right answer
The fifo and afifo filters buffer frames in front of a consumer, and they're the first thing people reach for after reading the warning. FFmpeg's modern filter framework already handles queuing between filters, so inserting fifo by hand doesn't repair a timestamp mismatch, it just raises how much skew the graph will swallow before complaining.
That makes it the correct choice in one situation: the offset is real, deliberate, and bounded. Two live feeds where one arrives a few seconds behind, or an intentional audio delay you've set with adelay, are legitimate buffering problems. A watermark loop running against a finite clip is not, and fifo will only convert a loud failure into a quiet memory climb.
Two knobs that look related are not. -thread_queue_size sizes the input demuxer's thread queue and shows up as "Thread message queue blocking". -max_muxing_queue_size sizes the output muxer queue and shows up as "Too many packets buffered for output stream". Neither touches the filter graph, and raising them wastes memory without changing a single dropped frame.
Common pitfalls
The mistakes below cost the most debugging time, in rough order of how often they bite:
- Silencing the log with
-loglevel error. The frames still drop, you just stop hearing about it, and the broken output ships. - Trusting the exit code. FFmpeg returns 0 after thousands of these warnings, so any pipeline that only checks the exit status will report success on a file with a frozen watermark.
- Adding
-shortestand assuming it's handled.-shorteststops the output at the shortest stream, but a looped input inside the graph keeps generating frames. The join itself needsshortest=1orduration=shortest. - Using
-c copyon normalized-looking inputs. If frame rates or sample rates differ,concaton copied streams will skew within a few seconds. - Letting the flood fill your logs. In a hosted runner this is a real cost: thousands of identical stderr lines per job will choke an n8n execution log or an AWS Lambda CloudWatch stream long before the video is wrong.
Normalize before the graph, not inside it
The durable fix for a pipeline isn't a better filter string, it's refusing to build a graph out of inputs you haven't measured. Probe each input first, rebase its timestamps, trim or pad to one shared timeline, and only then join. FFprobe is cheap next to a transcode, which is why the FFprobe reference belongs in the step you run before every job, not after a failure.
That ordering is what the hosted version does for you. FFmpeg Micro probes the inputs, aligns durations and timestamps, then runs the graph, so a watermark overlay or a mixed music bed doesn't depend on you remembering setpts at 1am. Billing is metered per second of input duration, so trimming 30 seconds out of an hour-long recording costs 30 seconds, not an hour, and failed jobs are never billed. One token buys 10 seconds of input, and a new account gets 200 with no card. The quickstart creates a temporary key and runs upload, transcode, poll and download in the dashboard, the fastest way to compare its output against the command you're fighting. If the graph lives inside an automation tool, the same call works from n8n over plain HTTP.
FAQ
Does "buffer queue overflow, dropping" mean my output is broken?
A few warnings at the start of a run usually leave the output intact, but a sustained flood means libavfilter discarded frames it could not pair, and the output is wrong in a way that's easy to miss: a frozen overlay, a stuttering stack, or drifting audio. Compare the output's duration and frame count with ffprobe before you trust it.
Why does FFmpeg still exit 0 after hundreds of these warnings?
Dropping queued filter frames is a warning in libavfilter, not an error, so FFmpeg finishes the mux and returns 0. Any pipeline that gates on exit status alone will mark the job successful, so check the output's measured duration and frame count instead of the return code.
How do I fix amix when my audio tracks are different lengths?
Decide which length wins and say so explicitly. amix=inputs=2:duration=shortest ends the mix with the shorter track, duration=longest keeps going and needs the short input padded with apad, and duration=first follows input one. Leaving the default in place while feeding a 3-minute music bed against a 40-second voiceover is what produces the overflow.
Why does the same command only overflow on Windows?
Frame dropping here depends on how fast each branch is fed relative to the other, so platform differences in process and pipe scheduling change whether the queue bound is hit. The 3D Slicer forum report in thread 17681 is a Windows-only symptom from a command that behaved on Linux. A graph with aligned timestamps doesn't care which OS it runs on, which is the real reason to fix the skew rather than tune the buffer.
If you'd rather stop hand-aligning durations for every overlay and mix, sign up free and run one of your current commands through the API with inputs that already disagree. The 200 tokens cover about 33 minutes of video, which is enough to find out whether normalization was the part you were missing.
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.
You might also like

FFmpeg "Impossible to Convert": Fix the Format, Not the Filter
FFmpeg impossible to convert between the formats supported by the filter? Two branches of your graph disagree on pixel format. Fix it before the overlay.

How to Upscale Video with FFmpeg (and When It Actually Helps)
FFmpeg upscale video the honest way: the lanczos scale command for 1080p and 4K, the bitrate math that decides how it looks, and when no scaler helps.

FFmpeg 9.0 verifies TLS: fix 'certificate verify failed
FFmpeg 9.0 verifies TLS by default, so 'ffmpeg certificate verify failed' kills HTTPS inputs that worked on 8.1.2. Fixes: -ca_file, CA bundle, tls_verify.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free