Nodes/ComfyUI MOSS-Image T8/MOSS-Image Official VAE Decode
ComfyUI Node

MOSS-Image Official VAE Decode

MOSS-Image Latents Aren't ComfyUI Latents — Here's the Translation Step

By T8mars·Created 15 days ago·Updated 15 days ago· 2
MOSS-Image Official VAE Decode
  • vae
  • latent
  • images
◄tiledfalse►

Plug the sampler's output into a normal VAE Decode and you get nothing useful, and it's not your fault - MOSS-Image latents are packed. The sampler emits a tensor of shape [B, 128, H/16, W/16], and stock decoding has no idea what to do with 128 channels at a sixteenth of the resolution. This node does the unpacking, then hands the result to the VAE and gives you a plain ComfyUI IMAGE that every other node in your graph already understands.

What it actually does

Three steps, in order, and all of them matter.

BN inverse. The FLUX.2 VAE keeps a BatchNorm in front of its decoder, so the latent the sampler produced is normalized. The decode multiplies by sqrt(running_var + eps) and adds running_mean - channel-wise, from the VAE's own buffers. Skip it and you get the classic grey soup that people misdiagnose as "wrong VAE" on older models; here it's just an unapplied transform.

2×2 unpack. The 128 packed channels are reshaped into 32 channels at twice the height and width, so H/16 becomes H/8. That's the shift from a packed latent to the spatial latent the decoder expects. It's the single most important reason you can't freelance with a different decoder node.

Decode in FP32. The VAE runs in single precision regardless of what the DiT did, then clamps to the standard range and postprocesses to a ComfyUI image tensor. That's the pack's stated design: "TE/DiT use BF16; VAE decoding uses FP32." Decoding is where the last few percent of color and fine texture live, and it's cheap enough at 0.25 GB to do properly.

The node is strict about its input, and honestly that's helpful: give it something that isn't a MOSS latent and it errors with "Connect MOSS-Image Official Sampler's MOSS_IMAGE_LATENT output," and if the channel count isn't 128 it tells you what shape it expected. You will not silently get a black image out of a mis-wire.

The inputs

Three, all required.

vae comes from the Official VAE Loader. latent comes from the Official Sampler - and only the sampler; the socket type MOSS_IMAGE_LATENT exists so this pairing can't drift. tiled defaults to false, and the author's own note is that tiling is optional and may change pixels. Believe that: it enables the VAE's tiling path, which is a memory lever, not a quality setting. If you're decoding 1024² on a card that fits, leave it off. If a big batch or a 2048² render OOMs at the decode step, turning tiled on is the first thing to try - then compare against a non-tiled decode before you ship the image, because the seams are real.

Output is images, a standard ComfyUI IMAGE. Save Image, Preview Image, an upscaler, a face detailer, whatever - from here you're back in normal ComfyUI land.

Install

Manager → ComfyUI MOSS-Image T8 (publisher t8star) → restart. Or:

cd ComfyUI
git clone https://github.com/T8mars/Comfyui-Moss-Image-T8 custom_nodes/Comfyui-Moss-Image-T8
python -m pip install -r custom_nodes/Comfyui-Moss-Image-T8/requirements.txt

And the VAE, which is the smallest download in the pack:

hf download t8star/Moss-Image-Comfy --local-dir models --include "vae/*"

That's 0.25 GB plus a .assets folder. Do keep the folder - the loader verifies the manifest - but note it's a trivially re-downloadable file, so don't spend an evening debugging it.

Where people get burned

"It's just a VAE Decode, can't I use the standard node?" No. Wrong channel layout, no BN inverse, no unpack. Two of the three things this node does don't exist upstream, and the failure isn't a crash, it's a nonsense image.

Grey or washed-out output. Genuinely rare here, because the decode is pinned and the VAE is the matching file. If you do see it, check you loaded moss-image-vae.safetensors and not a leftover SDXL VAE, and check you didn't swap the VAE file between workflows. The pack's hash verification catches a corrupted weight but not a valid-and-wrong one.

You tried to preview the latent. There's no Preview Latent path for this type, and no standard trick to fake one - the sampler hands back a dict with dimensional metadata and packed samples, not a LATENT dict. If you want to see intermediate progress, watch the sampler's step progress bar; don't go hunting for a decode shortcut.

OOM at decode on a 1024² batch. Decoding a batch of 16 at once is the usual culprit. Either drop batch_size on the sampler or flip tiled on and accept that the pixels may shift slightly.

Slowness that isn't the model. The VAE is loaded, used and released each run, because the pack refuses to keep all three components resident at once. First image after a restart pays a small load; subsequent ones don't, as long as you're not also flipping files around and invalidating the loader's fingerprint check.

CategoryMOSS-Image/Official

Inputs (3)

NameTypeDefaultDescription
vaeMOSS_IMAGE_VAE—
latentMOSS_IMAGE_LATENT—
tiledBOOLEANfalse—

Outputs (1)

NameTypeDescription
imagesIMAGE—