Nodes/OmniNodes/Latent QC Gate 🚧
ComfyUI Node

Latent QC Gate 🚧

The Night-Watch Gate That Stops a Corrupted Latent Before It Costs You a Run

By TensorVizionΒ·Created 3 months agoΒ·Updated about 8 hours agoΒ· 0
Latent QC Gate 🚧
  • latent
  • fallback_latent
  • latent
  • passed
  • reason
β—„check_nan_inftrueβ–Ί
β—„check_near_blanktrueβ–Ί
β—„variance_threshold0.0005β–Ί
β—„check_outlier_saturationtrueβ–Ί
β—„outlier_std_threshold4.0β–Ί
β—„outlier_percent_limit8.0β–Ί

You've queued a 500-image batch and gone to bed. At 3am one of them samples into a wall of NaN static, and the queue happily decodes it, saves it, and moves on. That's the failure mode Latent QC Gate exists to catch: an automated PASS/FAIL check on the latent itself, before VAE decode, with an optional fallback so the run doesn't die. It's the only thing in the pack that checks a LATENT tensor before it reaches VAEDecode - everything else assumes the sampler did its job. This node is the QA shift for your unattended renders.

How it works

Three independent checks, each toggleable:

  • check_nan_inf - flags NaN or infinity values. The nuclear failure; if you see this, something upstream genuinely broke.
  • check_near_blank - flags latents with variance below variance_threshold (default 0.0005). A suspiciously flat latent means the sampler produced nothing - the "black image" failure.
  • check_outlier_saturation - flags latents where more than outlier_percent_limit% of values sit more than outlier_std_threshold standard deviations out. This is the "content went off the rails" check.

If every enabled check passes, passed=True and the latent flows through unchanged. If any fails, it returns fallback_latent instead (if connected) and passed=False, with reason telling you exactly which check tripped. Without a fallback connected it returns the original latent anyway - silently handing downstream an empty tensor would break most graphs, which is a design choice worth respecting.

Why median/MAD (the detail that makes this node good)

The outlier check uses median/MAD, not mean/std - deliberately. The pack's changelog is unusually honest about this: an earlier mean/std version failed a constructed test where 20% of a latent's values were extreme outliers, because a large contaminated fraction pulls the mean and standard deviation along with it, hiding the very values that should trip the check. Mean/std have a 0% breakdown point; median/MAD survive up to 50% contamination. In plain terms: the automated gate is engineered not to be fooled by a big bad batch, which is exactly the scenario an overnight run throws at it. Note the pack's Latent Histogram still uses mean/std for its chart stat - different purpose, different statistic, don't expect matching numbers.

Inputs and outputs

  • latent - in.
  • The three check toggles plus variance_threshold, outlier_std_threshold, outlier_percent_limit.
  • fallback_latent (optional) - returned when a check fails.
  • latent, passed, reason - out.

The passed boolean is the useful part: wire it into a Conditional Gate to skip the decode/save chain on a failed batch item, or into the pack's Discord Notify to get pinged only when something actually goes wrong - the "wake me if it breaks" pattern.

Install and troubleshooting

No extra dependencies:

cd ComfyUI/custom_nodes
git clone https://github.com/TensorVizion/OmniNodes

Restart, find it under TensorVizion/Latent (ComfyUI Manager, search "OmniNodes", also works).

  • Everything fails, all the time. Your thresholds are too tight, or your upstream is genuinely broken. Check reason - it names the check. Loosen outlier_std_threshold (default 4) before touching the near-blank variance threshold.
  • Nothing ever fails. With default thresholds on healthy runs, that's the goal. If you suspect it's not firing, feed it a deliberately corrupted latent (the pack's Latent Noise Inject at high strength is a handy test tool) and confirm it catches it.
  • The workflow still saves garbage. The gate only stops what you wire it to stop. passed is a signal; you have to gate the downstream chain on it.

Set it, connect the fallback, wire passed into your save path, and forget about it. That's the whole point - a node that earns its place by being boring at 3am.

CategoryTensorVizion/Latent

Inputs (8)

NameTypeDefaultDescription
latentLATENTβ€”
check_nan_infBOOLEANtrueβ€”
check_near_blankBOOLEANtrueβ€”
variance_thresholdFLOAT0.00050–1β€”
check_outlier_saturationBOOLEANtrueβ€”
outlier_std_thresholdFLOAT4.00.5–15β€”
outlier_percent_limitFLOAT8.00.1–100β€”
fallback_latentoptLATENTβ€”

Outputs (3)

NameTypeDescription
latentLATENTβ€”
passedBOOLEANβ€”
reasonSTRINGβ€”