ANDRO VAE Encode
If you feed a float32 EXR plate into a stock VAE Encode, you just threw the precision away
- pixels
- vae
- latent
- report
VAE Encode (float32) is the mirror image of this pack's headline node, and it exists because the encode side has the same blind spot going the other way. Stock ComfyUI casts your input image to the VAE's working dtype - usually bfloat16 - before the weights ever see it. So when you carefully round-trip a float32 EXR plate back through a VAE, the precision you saved on the decode side is discarded at the door. The pixels get quantised to bf16 on the way in, and nothing downstream can tell the difference happened.
This node casts both the encoder weights and vae_dtype to float32 before encoding, then restores the originals in a finally block. It's a thin wrapper - the same guarded cast logic as VAEDecodeFloat32 (quantised weights that refuse the cast fall back gracefully with a note in the report), just aimed at vae.encode() instead of vae.decode().
Inputs
There are only three, and the two you'll actually touch:
pixels- the IMAGE batch. Feed it what the rest of your float32 decode chain produces. An ordinary 8-bit PNG in, you won't see much benefit; a float32 EXR in, this is where that precision stops leaking away.vae- fromVAELoader, same as stock.precision-float32(default) orvae default.vae defaultreproduces stock exactly; useful as the control side of an A/B run.
Outputs
latent- a standard LATENT, wired into whatever the stockVAEEncodefeeds.report- a STRING with the input's min/max and the latent's shape/dtype, plus a note if the float32 cast was skipped. Read it in the console or wire it to a text display; it tells you whether you actually got float32 or a silent fallback.
When this pays off
Honestly, it's a niche node - you only care if you're re-encoding material, not generating fresh. The scenario that makes sense: you decoded to float32 EXR for a grade, did the grade in Resolve or Nuke, and now you want to bring the graded plate back into a generation (inpainting a changed region, an img2img pass, a second model's conditioning). That's a real VFX-loop workflow, and this is the node that stops your hard-won headroom from evaporating on the way back in. The pack's own LTX2.5_float32_EXR.json example is built around a one-way trip, but the encode node is there for the round-trip.
If you never feed float32 pixels into a VAE, you don't need this node. That's not a knock - it's the honest scope. Skip the hype, install it, and it costs you nothing when unused.
Install
Same as the rest of the pack - ComfyUI Manager (search "comfyui-vae-float32"), or:
cd ComfyUI/custom_nodes
git clone https://github.com/AndreiOrehov/comfyui-vae-float32
Then restart. No models to download, and the only extra dependency worth knowing about is OpenEXR, which you only need if you also want EXR output. Everything else rides on what ComfyUI already ships.
One thing to know before you file a bug: like its decode sibling, this node reaches into vae.vae_dtype and the VAE's weights - not public API. If a ComfyUI update changes how the VAE is structured, the guarded fallback means you get stock behaviour plus a note, not corruption. If you're ever unsure whether float32 actually took, compare against vae default with Image Compare (numeric) from the same pack rather than trusting your eyes.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| pixels | IMAGE | The image to encode. A float32 EXR plate keeps its precision here only if precision is float32. | |
| vae | VAE | The VAE that belongs to the model. A VAE is trained together with its model - pairing one model's latents with another's VAE does not fail loudly, it just decodes wrong. | |
| precision | COMBO | float32 | 'vae default' casts the plate to the VAE's dtype (usually bfloat16) before the weights see it, which throws away a float32 EXR's precision at the door. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | The encoded latent. |
| report | STRING | The range of what was handed in, measured BEFORE the latent exists, so out-of-range input is seen rather than inferred afterwards. |