NVFP4 SDXL Dual CLIP Loader
Your NVFP4 SDXL CLIP files won't load in ComfyUI — this node is the fix
- clip
You've got a pair of NVFP4-quantized SDXL text encoder files, you point ComfyUI's normal DualCLIPLoader at them, and it either throws up or just won't parse the weights. Not your fault, and not a corrupt download. NVIDIA's Model Optimizer (the tool that spits out those FP4 dumps for Blackwell GPUs) writes text encoders in a packed format ComfyUI's stock loaders were never taught to read. NVFP4 SDXL Dual CLIP Loader is the bridge: it reads the packed files, unpacks them back to plain fp16 weights, and hands you a bog-standard CLIP object the rest of your SDXL graph already knows how to use.
The honest pitch: it's about the files, not speed
NVFP4 is NVIDIA's 4-bit float format - FP4 E2M1, eight values plus sign, two of them squeezed into every byte. On the diffusion-model side, it's the rung below fp8 that the community treats as "fast on RTX 50-series, but fine details like eyes start to soften" (the KB files it as the emerging frontier under fp8). For a text encoder, though, the stakes are much lower: the SDXL CLIP pair is small, and quantizing the encoder loses far less than quantizing the UNet - it's the same reasoning that made fp8 T5 the first thing Flux users switched.
But note what this node does not do. It dequantizes at load time, on the CPU, into fp16 tensors in VRAM. You do not get Blackwell NVFP4 compute, and you do not shrink VRAM during generation compared to a normal SDXL CLIP. What you get is the ability to use the files at all, plus a smaller download sitting on your disk. If your actual goal is a lighter SDXL pipeline, plain fp8 is the mainstream answer and saves you the same ~0.5GB with zero ceremony. Reach for this loader when NVFP4 is what you have - a TensorRT/ModelOpt export, or one of the FP4 CLIP dumps floating around - not when you want the cheapest possible SDXL.
How it works
The loader pulls both files from ComfyUI's models/clip folder, then figures out which is which by inspecting the weights: a q_proj shaped 768×768 means clip_l, 1280×1280 means clip_g ("the common name from sdxl", as the author puts it). If you swap the slots it detects it and swaps them back, logging a warning. Each packed weight is unpacked nibble-by-nibble through an E2M1 lookup table, scaled by per-16-weight block scales (stored as fp8_e4m3fn), optionally multiplied by a second global scale tensor, scrubbed of any NaN/Inf, and emitted as fp16. It then builds a normal SDXLClipModel + SDXLTokenizer pair via ComfyUI's comfy.sd.CLIP. The dequantized result is cached per file + modification time, so re-running a workflow doesn't redo the math - first load is the slow one.
Inputs and the output
Four inputs, and only two of them should ever require thought:
- clip_l_file / clip_g_file - dropdowns listing your
models/clipfolder. Pick the two NVFP4 safetensors. As above, the node auto-detects roles and even auto-swaps, so a wrong label is survivable. - nibble_order (
lo_hidefault, orhi_lo) - which nibble of each packed byte comes first. Leave it unless the output looks wrong. - apply_global_scale2 (
truedefault) - whether to apply the second scale tensor from the ModelOpt format. Leave it on; it's what the exports expect.
Output is a single clip (type CLIP) - wire it into CLIPTextEncodeSDXL exactly like you would any DualCLIPLoader output.
Install
Via ComfyUI Manager, search SDXLNVFP4 (or "NVFP4 SDXL"). Or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/Apache0ne/ComfyUI-SDXLNVFP4
Then restart ComfyUI. The pack has no dependencies beyond what ComfyUI already ships and no model downloads in-repo - you supply the two safetensors yourself.
Where people get burned
- "Could not resolve '…' in ComfyUI models/clip folder" - the file isn't in
models/clip. The dropdowns only show what's there; both files must be in that folder, not in your downloads. - "Could not form SDXL dual clip pair" - you picked two files that decode as the same role (both clip_g, say). Pick one of each.
- A warning about clip_l/clip_g being "auto-swapped" - fine, the node fixed it; but double-check you didn't consistently mislabel things elsewhere in the workflow.
- Conditioning that comes out like garbage - try flipping
nibble_ordertohi_lo; the pack's defaultlo_himatches the author's exports, not every exporter's. - Console lines about "sanitized N non-finite values" - the loader turns NaN/Inf into zeros to keep the load alive. A small count is normal hygiene; a huge one usually means a corrupted or mismatched file, so re-download before chasing anything else.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| clip_l_file | COMBO | 0 options: | |
| clip_g_file | COMBO | 0 options: | |
| nibble_order | COMBO | lo_hi | 2 options: lo_hi, hi_lo |
| apply_global_scale2 | BOOLEAN | true | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| clip | CLIP | — |