ComfyUI 14B fp8 VRAM Crash? How block_swap and offload_device Actually Work

You downloaded a 14B fp8 checkpoint, wired up the workflow, hit Queue, and watched the terminal print the three words every local-AI tinkerer dreads: CUDA out of memory. The model file is 16 GB. Your GPU reports 15 GB. On paper the numbers are close—close enough that forcing it feels like it should work. In practice, whether it works comes down to two settings most people never read the source to understand: block_swap and offload_device.

This guide is written from a real migration: moving a 16.1 GB Wan2.2-Animate-14B-fp8 checkpoint onto a 15 GB RTX 5060 Ti. The model exceeds the card, so the only way it runs at all is by swapping and offloading transformer blocks on demand. The notes below are grounded in the actual node source (Kijai’s ComfyUI-WanVideoWrapper) and the official Wan2.2 repository, not from re-reading a tutorial. Let’s unpack each mechanism, in the order the model loader actually applies them.

Why a 16 GB model on a 15 GB card is a real problem

First, the arithmetic that trips everyone up. A .safetensors file of ~16 GB represents the serialized weights. When ComfyUI loads them in fp8, the resident size is roughly that number, but inference also needs activations, the text encoder, the VAE, and clip vision. None of that is free. The official Wan2.2 repository is explicit about the ceiling: its single-GPU generate.py for the A14B models states the command “can run on a GPU with at least 80GB VRAM,” while the compact TI2V-5B variant is the one documented to run on a 24 GB RTX 4090.

So a 14B model that tips over 15 GB sits in an awkward middle ground: too big to fit naively, small enough that a few GB of clever swapping should bridge the gap. That bridge is exactly what block_swap and offload_device provide—but only if you set them deliberately, because the defaults are conservative on purpose.

What block_swap actually does (and what it does not)

In the WanVideoWrapper node source, the model loader accepts a block_swap_args input and injects it into the transformer’s options as transformer_options["block_swap_args"]. This is a ComfyUI native feature, not a wrapper hack: it tells the diffusion transformer to keep only a slice of its blocks resident in GPU memory and page the rest from system RAM (or disk) as the sampler walks through them.

The number you set is a count of transformer blocks held in VRAM, not a byte value. Lower = less VRAM = more swapping = slower. On a 14B MoE model a common starting point is 20, which is also what many community Wan workflows default to. There is no “correct” value that works everywhere: the right number is a function of how many blocks the model has and how much VRAM you can spare after the encoder and VAE take their cut.

Two misconceptions to clear up immediately:

  • Block swap is not quantization. Swapping moves weights between fast and slow memory; it changes speed, not precision. Your fp8 weights stay fp8.
  • Block swap does not shrink the model. If you set it too high, you still OOM; too low, and generation crawls because every other block is a round-trip to CPU RAM.

offload_device and load_device: where things live between passes

The second half of the pair is the device routing. The wrapper pulls unet_offload_device() from ComfyUI’s model manager and, on the decoder side, moves the VAE, clip vision, and the video model onto offload_device before each encode. The force_offload flag you see sprinkled through the node defaults to True, which is what makes sequential workflows behave: after a component finishes its job, it is explicitly moved off the GPU instead of lingering in VRAM.

The practical consequence matters more than people realize. In a three-stage pipeline—text encode, then VAE/latent work, then the diffusion transformer—every one of those stages competes for the same 15 GB. Without force_offload, the text encoder you finished with eight seconds ago is still squatting on VRAM when the transformer tries to allocate, and you OOM on a stage that would have fit fine in isolation.

Here is the interaction to internalize: block_swap controls VRAM within the transformer’s forward pass; offload_device controls VRAM between stages. You need both. Setting block_swap to 4 but leaving the clip vision and VAE resident defeats the point, just as aggressively offloading everything but never capping the block count leaves the transformer itself overflowing.

A reproducible sequence for the 16 GB case

Rather than give you a magic number, here is the diagnostic sequence that surfaces the actual ceiling on your card. Run it once, in order, and watch nvidia-smi at each step (not just the final frame):

  1. Baseline the card. With nothing queued, note free VRAM. If another process (a local LLM server, a second ComfyUI) is already holding gigabytes, that is your real budget, not the 15 GB on the box.
  2. Load the model with block_swap at a high default (e.g. 20+). If it OOMs at load time rather than at sampling, your problem is not swap count—it is that the weights plus the encoders don’t fit at all, and you need a smaller quantization or a lighter encoder.
  3. If it loads but dies on the first denoise step, lower block_swap incrementally (20 → 12 → 8) until the transformer’s resident footprint fits. Each drop costs speed, so stop at the highest value that stays under the ceiling.
  4. Confirm force_offload is on for the text encoder, clip vision, and VAE so intermediate tensors don’t stack on top of the transformer.
  5. Re-check between stages, not after. OOM late in the run is usually a stage-boundary leak, not the model being too big.

On this concrete case, the honest outcome of step 2–3 is worth stating plainly: a 16.1 GB fp8 checkpoint on a 15 GB card is genuinely at the edge, and the reliable fallback is the smaller 14B fp8 variant already on disk or the official 5B model, which the README explicitly targets at consumer cards. For more context on how these video models stack up against their closed-source rivals, see our earlier breakdown of Wan2.2 Animate versus the commercial options, and for the full consumer-hardware stack, running Wan2.2, CogVideoX and Mochi locally.

Common traps that masquerade as “not enough VRAM”

Most “OOM” reports are actually one of these four, and none are fixed by buying a bigger GPU:

  • Leftover resident tensors. A prior run’s encoder or VAE still held in VRAM because force_offload was off. Residual memory makes the next run fail, which is why failures look intermittent.
  • Wrong quantization for the card. fp8 e4m3fn is the sweet spot here; bf16 double weights won’t fit at all, and a mistagged dtype means you’re loading more precision than you think.
  • The text encoder is the hidden hog. A full-precision umt5-xxl encoder alone can eat several GB. Offload it (or use its fp8 variant) before blaming the transformer.
  • Resolution, not the model. At 480×832 for 49 frames the activation overhead is manageable; jump to 720p and the same model and block_swap value blow past the ceiling. OOM is often a resolution decision, not a model-weight problem.

How to verify a fix instead of guessing

The verification step is where most local-AI troubleshooting falls apart, because “it didn’t crash this time” is not evidence—it might just be a favorable seed or an empty queue. Verify with a deliberate loop:

  1. Run the same workflow, same seed, three times in a row. One clean pass is luck; three is a configuration.
  2. Watch peak VRAM across all three, not the average. A fix that leaves 200 MB of headroom only survives because of scheduling; give yourself at least a gigabyte of margin.
  3. Compare generation time at the chosen block_swap value against the next-higher one. If dropping from 12 to 8 saves VRAM but doubles time, you found your speed/headroom trade-off point.

That three-run, nvidia-smi-watched loop is the difference between “it worked once” and a workflow you can actually queue overnight without babysitting.

Conclusion

A 14B fp8 model that’s a hair bigger than your VRAM is not a lost cause—it’s a budgeting exercise. block_swap caps how much of the transformer lives on the GPU at once, and offload_device / force_offload decides what else gets to sit there between stages. Set the first to the highest count that doesn’t blow the ceiling, keep the second on for every non-transformer component, and confirm with a repeated same-seed run watching peak (not average) VRAM. When the file genuinely won’t fit even at minimum swap, fall back to a lighter quantization or the 5B consumer-targeted model—that’s not surrender, it’s selecting the right tool for a 15 GB card.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *