You sized your checkpoint to fit comfortably in VRAM. The sampler step completes without a hitch. Then, at the very last moment — the moment you actually want to see the image — ComfyUI throws torch.cuda.OutOfMemoryError at the VAE Decode node. The workflow was 95% done, and it died at the finish line.
This is one of the most confusing OOMs in local Stable Diffusion because it happens after the part everyone thinks is memory-heavy. The diffusion UNet is no longer allocating; the model is idle. So why did VRAM spike at decode time? The answer is that the VAE is a separate, independently-allocated model with its own precision and its own memory profile — and ComfyUI’s launch flags let you control each of these independently. This guide walks through why the decode step OOMs, how to confirm it, and which exact flags and settings fix it without touching your diffusion model.
Why the VAE Decode Step Is a Separate Memory Spike
The misunderstanding starts with treating your workload as “one model.” It is not. A Stable Diffusion pipeline is several models loaded and unloaded in sequence:
- Text encoder / CLIP — runs first, produces conditioning.
- UNet (diffusion model) — the big memory consumer during sampling.
- VAE decoder — runs last, converts the latent tensor into pixel-space RGB.
ComfyUI’s default behavior loads each model when needed and offloads it afterward to conserve VRAM. By the time sampling finishes, the UNet has been released. When the VAE runs, it is allocated fresh. If the VAE itself — plus the latent, plus intermediate buffers — exceeds what is left after the operating system, the GUI, and any lingering model weights are accounted for, you hit OOM. The failure has nothing to do with your diffusion model being “too big” for your card.
A second, subtler cause is precision. VAE decoders are notoriously sensitive to reduced precision, and running them in fp16 can produce black images — an entirely different failure mode with its own flag (more below). The point for now is that the VAE’s memory and precision are controlled separately from the UNet’s, and that separation is exactly what makes the decode step behave like a hidden second model.
Confirming the OOM Is Actually the VAE
Before changing any flag, confirm you are looking at the decode step and not something else. Three diagnostics will pin it down.
1. Read the node title in the error. ComfyUI wraps node execution failures with the node’s ID and type. If the traceback names VAEDecode (or VAEEncode on the img2img side), you know the VAE node is the boundary. If it names the KSampler or a UNETLoader, your problem is upstream and this guide is not the right fit.
2. Watch the VRAM curve, not the peak. The timing of the failure matters. A decode OOM surfaces after the sampler progress bar reaches 100% and the UI has already shown you the latent preview. If you can reproduce the crash reliably at that exact step across multiple seeds, you have a decode-stage allocation problem, not a random sampling spike.
3. Try a tiny latent first. Temporarily set the empty latent to something like 256×256 (or the smallest multiple-of-8 your workflow tolerates) and re-run. If the OOM disappears at small resolution and returns only as you scale the latent up, the VAE decode allocation is tracking the latent size — direct evidence that decode is the memory cliff.
None of these steps require a GPU monitoring tool or a benchmark. They are all observable in the standard console output and UI.
Fix 1: Move the VAE Off the GPU with –cpu-vae
The single most direct fix, and the one that requires no model changes, is to run the VAE decoder on the CPU. ComfyUI exposes this as a launch flag:
--cpu-vae
The flag is documented in ComfyUI’s comfy/cli_args.py as “Run the VAE on the CPU.” It trades decode speed for stability: the CPU has access to far more addressable memory than VRAM, so a decode that OOMs the GPU will still complete on system RAM. On a 16 GB card that was sitting near its ceiling after sampling, offloading the VAE is frequently the difference between a finished image and a killed job.
There is a real cost. CPU decoding of large latents is slow — a 1024×1024 or larger image can take several seconds to decode rather than a fraction of a second. For batch work or interactive iteration this is painful; for one-off large generations it is often perfectly acceptable. Treat it as a reliable fallback, not a default.
The VAE-related precision flags live alongside it and are worth knowing even if you stay on the GPU. Running the VAE in fp16 is a documented cause of black images; the flag --fp16-vae explicitly warns “might cause black images,” and --fp32-vae forces full precision to avoid artifacts. If you move the VAE to CPU and suddenly get solid black output, the precision flags are the second dial to check.
Fix 2: Decode in Tiles to Cap the Memory Footprint
If you need to keep the VAE on the GPU for speed, the alternative to offloading is to bound its memory use with tiled decoding. Tiling splits the latent into overlapping patches, decodes each independently, and blends the seams. The peak allocation is capped at roughly the size of a single tile rather than the full latent.
ComfyUI ships tile controls directly in the VAEDecode node: a tile_size parameter (often 512 by default in tiled variants) and a temporal_size / tiling toggle depending on the node version. The mechanics are straightforward: smaller tiles lower the peak memory but increase seam blending time. Start at 256 and work upward if you are still OOMing at 512.
A practical caveat worth stating clearly: tiling is not a free lunch for quality. Because the VAE is effectively a Gaussian window that overlaps patch boundaries, aggressive tiling can introduce faint seams or slight color shifts along tile edges. For most photographic or illustrative outputs the artifacts are imperceptible, but for flat-color or very high-contrast images they occasionally show. Test a representative image before committing tiling as your permanent setting.
Fix 3: Tell ComfyUI How Much VRAM to Hold Back
The third lever is tuning how aggressively ComfyUI holds models in VRAM, so the VAE has room to be allocated in the first place. Three related flags govern this, all documented in the same CLI argument file:
--vram-headroom <GB>— reserves a margin of free VRAM that ComfyUI tries to keep genuinely unused. Give the VAE (and the OS) breathing room by setting a small headroom rather than running at the red line.--reserve-vram <GB>— reserves an amount for the OS and other software, so the card is not treated as fully available to ComfyUI.--disable-smart-memory— forces ComfyUI to aggressively offload to system RAM instead of keeping models in VRAM when it can. This is the opposite of the default “smart” behavior, and it can free enough VRAM at decode time on constrained cards.
The default caching mode (--cache-ram) already offloads model weights by RAM-pressure thresholds. If you are on a 16 GB card and the decode OOM persists despite tiling and headroom, combine a small --vram-headroom with --cpu-vae for the decode step itself. The flags compose; they are independent dials.
A common trap is reaching for --lowvram or --novram and expecting them to fix a decode problem. Those flags govern the text encoder and model-weight placement when dynamic VRAM is not in use — they are not a VAE control. Using them to chase a decode OOM usually just slows down the whole pipeline without addressing the allocation that is actually failing.
Verifying the Fix Really Worked
After applying any of these changes, verify deliberately rather than assuming the crash is gone because one image rendered.
1. Re-run at the resolution that failed. Do not test at a smaller size. The exact latent that OOM’d before is the only meaningful proof. Run it two or three times across different seeds to rule out a lucky low-water moment.
2. Watch the log line, not just the image. ComfyUI logs model load/unload. After the fix, confirm the VAE is actually being offloaded to CPU (or tiled) in the output — a silent success with no change in behavior means the flag was not applied, often because the launch command was edited in one place but the server was started from another.
3. Check for the precision failure mode you may have swapped in. If you enabled --fp16-vae or changed precision, inspect the output for pure-black frames, not just for the memory error being gone. Solving an OOM by introducing black images is not a fix.
The complete symptom-to-resolution path, from fastest to most thorough, is: confirm the failing node is VAEDecode → tile the decode → add VRAM headroom → fall back to --cpu-vae. Most 16 GB cards will resolve at one of the first two steps; the CPU fallback is the guaranteed escape hatch when nothing else leaves room.
For the broader picture of VRAM management across a whole open-source pipeline — not just the VAE — see our walkthrough of running Wan2.2, CogVideoX, and Mochi on consumer hardware, and for the specific case of a large motion model squeezed onto 16 GB, the Wan2.2 Animate 14B BlockSwap guide.
Conclusion
A VAE decode OOM is not evidence that your GPU is too small for your diffusion model. It is evidence that two independent models — the UNet and the VAE — were being asked to share a memory budget that was never balanced between them. The tools to fix it are already in ComfyUI’s launch flags and node parameters: --cpu-vae to offload the decoder, tiled decoding to cap its allocation, and --vram-headroom / --reserve-vram / --disable-smart-memory to leave it room. Diagnose the failing node first, change one dial at a time, and verify at the exact resolution that failed — and the mystery ‘OOM at 95%’ becomes a straightforward memory-budgeting problem.
For the authoritative list of launch flags and their descriptions, consult the ComfyUI cli_args.py source, which documents every flag referenced in this guide.
Leave a Reply