Latent Statistics
Know whether that latent is broken before you decode it
- samples
- index
- mean
- std
- min
- max
- absolute_mean
- batch_size
- channels
- height
- width
- is_finite
- summary
Every ComfyUI user has had the moment: the sampler ran, the VAE decode ran, and out came a black frame, or a grey one, or a garble, with nothing in the console saying why. A sampler that diverged doesn't throw an error - it answers a latent full of nan or huge values, and the failure only becomes visible after you've paid for the decode. WAS Latent Statistics measures the values inside a latent, not its size, so you can catch the wreck before it hits the VAE.
The inputs are samples plus how you want to measure it. scope picks whole batch (one set of figures for every latent together) or one latent (just the one index picks, counted from 0, negatives from the end, decimals truncated). Feed out_of_range to decide what happens when the index misses: wrap cycles around, clamp pins to the edge, error stops the prompt and names the batch size. The defaults are sane - whole batch, index 0 - so you can just wire a latent in and read.
The outputs read like a medical chart for your tensor:
meanandstd- the average and the spread. Fresh noise sits around mean 0, std ~1. A denoised latent drifts near 0 and moves with content, so compare between runs of one workflow rather than against a fixed figure. Astdof 0.0 means an Empty Latent Image (all zeros) or a result that collapsed to a flat block - both worth knowing before decode.minandmax- together, the range. An ordinary SD latent stays inside roughly -10 to 10; a much wider range is a sampler running away.maxcomes backinfwhere the sampler overflowed.absolute_mean- the average with signs dropped, so positives and negatives cancelling out can't hide a strong latent. Near 0.0 means empty or collapsed whatevermeansays.batch_size,channels,height,width- the shape facts.channelsis the one to test before handing a latent to a different model than the one that made it: 4 for SD1.5 and SDXL, 16 for SD3, Flux and Wan. Height/width are in latent rows (an eighth of the decoded pixels: 64 here decodes to 512).batch_sizecan drive a loop's iterations if you want to walk the batch one latent at a time.is_finite- false where any value is nan or inf, which is exactly what a diverging sampler leaves behind.summary- every figure on one line, for a log or to burn into a frame with Image Draw Text.
The design intent is visible in the output list: this is a guard node, not a curiosity. The is_finite boolean exists to be wired into a gate - the tooltip names it: "Wire it into Any Gate so a broken run stops before the VAE decode instead of saving a black frame." Batch rendering unattended, loop runs, or any long pipeline where a single divergence wastes an hour - that's where this earns its place. The channels readout doubles as a sanity check when a workflow you downloaded expects a different model family than you loaded, a classic source of silent garbage.
One honest limitation, stated in the tooltips: mean is nan when any measured value is nan, so on a genuinely broken latent most numbers go useless at once - but that's precisely when is_finite does its job.
Install
Ships in WAS Node Suite v3. ComfyUI Manager, search "WAS Node Suite", or:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/was-node-suite-comfyui
Restart after. Needs ComfyUI 0.14.0+ and Python 3.10+. No pip packages, no model downloads - it reads tensors ComfyUI already holds (v3 carries none of the old pack's install baggage).
Common issues
- Black frames with no console error. Wire
is_finiteinto a gate between the sampler and the VAE decode so a broken run stops instead of saving garbage. - Latent decoded by the wrong model. Check
channelsbefore decode - 4 vs 16 is the tell for SD-family vs SD3/Flux/Wan. - Std reads 0.0 on a "finished" sample. That's a collapsed or empty latent, whatever the image looks like after a heroic decode.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| samples | LATENT | The latent to measure, from a sampler, a VAE Encode or an Empty Latent Image. It is read, never changed. A video latent shaped [batch, channels, frames, height, width] is measured the same way. | |
| scope | COMBO | whole batch | What to measure. `whole batch` answers one set of figures for every latent together; `one latent` measures the one the index picks. |
| index | INT,NUMBER,FLOAT | 0-16384–16384 | Which latent to measure, read only when scope is `one latent`. Counts from 0, and negatives count from the end: -1 = last, -2 the one before it. A decimal is truncated: 2.7 = 2. |
| out_of_range | COMBO | error | Index outside 0..batch_size-1, which index -1 never reaches. With 3 latents and index 4: `wrap` = latent 1, `clamp` = latent 2, `error` stops the prompt and names the batch size. |
Outputs (11)
| Name | Type | Description |
|---|---|---|
| mean | FLOAT | Average of every value measured. A denoised latent sits near 0.0 and drifts with the content, so compare it between runs of one workflow rather than against a fixed figure. nan when any value measured is nan. |
| std | FLOAT | Spread of the values around the mean, over all of them rather than a sample. Around 1.0 for fresh noise. 0.0 for an Empty Latent Image, which is all zeros, and for a result that has collapsed to a flat block. |
| min | FLOAT | Smallest value measured. With max it gives the range: an ordinary SD latent stays inside roughly -10 to 10, and a much wider range is a sampler running away. |
| max | FLOAT | Largest value measured. inf where the sampler overflowed, which is also what turns is_finite false. |
| absolute_mean | FLOAT | Average of the values with their signs dropped, so positives and negatives cancelling out cannot hide a strong latent. Near 0.0 means an empty or collapsed latent whatever mean says. |
| batch_size | INT | How many latents the batch holds, whatever index was set. Wire it into a loop's iterations to walk the batch one latent at a time. |
| channels | INT | Channels each latent carries: 4 for SD1.5 and SDXL, 16 for SD3, Flux and Wan. Worth testing before a latent is handed to a different model than the one that made it. |
| height | INT | Latent rows, an eighth of the decoded pixel height: 64 here decodes to 512 pixels. 0 for a latent with no rows, such as an audio one. |
| width | INT | Latent columns, an eighth of the decoded pixel width: 64 here decodes to 512 pixels. |
| is_finite | BOOLEAN | false where any value measured is nan or inf, which is what a diverging sampler leaves behind. Wire it into Any Gate so a broken run stops before the VAE decode instead of saving a black frame. |
| summary | STRING | Every figure on one line, as `index=all batch_size=1 channels=4 ... non_finite=0`. For a log, a console print, or burning into a frame with Image Draw Text. |