Lenient Switch
The ComfyUI switch that lets each slot argue for itself
- source_a
- source_b
- source_c
- source_d
- source_e
- pass_if_a
- pass_if_b
- pass_if_c
- pass_if_d
- pass_if_e
- output
- matched
Most switch nodes in ComfyUI are dumb in a specific way: five inputs, a dropdown, whatever you pick wins. The choice is always yours. Lenient Switch (class LenientSwitch) is for when you want the graph to decide instead. Each of its five slots can carry its own truthiness test, the node evaluates them automatically in order, and the first one that passes gets its source forwarded downstream.
The core idea, per slot:
source_X- the value to forward if that slot wins (any type).pass_if_X- an optional condition that decides whether the slot wins. If it's not connected,source_Xis tested against itself.
Wire a mask into pass_if_a and you've got "forward the image when the mask is non-empty" with zero extra nodes. "Pick a prompt based on a flag" is the same shape with a string and a boolean. That decoupling is the whole point of the pack: most switchers force you to test the thing you forward; this one lets the condition be a different signal entirely.
How it works
Slots are tested A → B → C → D → E and the first truthy condition wins; its source_X is forwarded. None is always falsy. Four toggles decide what else counts as falsy: treat_zero_as_false, treat_empty_string_as_false, evaluate_boolean, and treat_empty_list_as_false. They all default on, which is the lenient part - a 0, an empty string, or an empty list quietly doesn't pass. The surprising one is evaluate_boolean: when you turn it off, booleans are always truthy, even False. Flip that only if you're gating on "this input is connected at all" rather than its value.
Outputs are two: output (any - the winning slot's source, or None if nothing matched) and matched (BOOLEAN). The second is the quiet hero. It's the only way to find out the switch silently failed instead of handing you a None that then explodes somewhere downstream.
Where people get burned
pass_if_*is not a CONDITIONING input, despite the name - the tooltip says so explicitly. You're wiring masks, ints, strings, whatever, not a prompt-conditioning tensor. This is the first-run confusion, and it's an easy trap when the node sits next to conditioning-heavy graphs.- All-falsy gives you
Noneonoutput, andNoneflows downstream like it's fine until your save node screams. Turn onblock_on_all_falseand the node emits anExecutionBlockerinstead, which halts downstream execution - the honest failure mode. bypass_unselectedis lazy evaluation done ComfyUI-natively: a slot whosepass_if_Xis connected and falsy is skipped before its source ever runs, so an expensive upstream chain feeding a guaranteed loser never executes. It's not an rgthree-style visual bypass - nothing greys out, the nodes just never run. The catch: slots with an unconnectedpass_ifcan't be skipped in advance, because their condition is the source value, which you only learn by running it.
Install
ComfyUI Manager → search "Lenient Switch" → install → restart. Or the manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/id-fa/ComfyUI-Lenient-Switch lenient-switch
Restart ComfyUI. That's the entire install: the pack's dependencies = [], no models to download, no Python packages, just Python 3.10+. The three nodes land under Lenient Switch in the node menu.
The wider picture
This is the good kind of any-type node. The ecosystem has a real backlash against wildcard routing - the "Please Stop using the Anything Anywhere extension" thread captured it - because invisible routing makes graphs impossible to debug. Lenient Switch earns its * inputs by being explicit about why a slot wins: every decision is a wire you can see. If your workflow gates one thing on the state of another - a mask's non-empty, a flag, a step count - this is the node you'll actually reach for.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| source_a | * | Pass-through source for slot A (any type). | |
| treat_zero_as_false | BOOLEAN | true | — |
| treat_empty_string_as_false | BOOLEAN | true | — |
| evaluate_boolean | BOOLEAN | true | — |
| treat_empty_list_as_false | BOOLEAN | true | — |
| block_on_all_false | BOOLEAN | false | — |
| bypass_unselected | BOOLEAN | false | When ON, slots whose pass_if_X is connected AND falsy are skipped WITHOUT evaluating their source_X, so that source's upstream chain does not run (lazy evaluation). Slots whose pass_if_X is unconnected are always evaluated (their winner can only be known at run time). Note: nodes are not visually bypassed like rgthree; they simply do not execute. |
| source_bopt | * | Optional pass-through source for slot B (any type). | |
| source_copt | * | Optional pass-through source for slot C (any type). | |
| source_dopt | * | Optional pass-through source for slot D (any type). | |
| source_eopt | * | Optional pass-through source for slot E (any type). | |
| pass_if_aopt | * | Per-slot truthiness test (NOT a CONDITIONING input). When connected, this value decides whether the matching source_X is forwarded; if unconnected, source_X is tested against itself. | |
| pass_if_bopt | * | Per-slot truthiness test (NOT a CONDITIONING input). When connected, this value decides whether the matching source_X is forwarded; if unconnected, source_X is tested against itself. | |
| pass_if_copt | * | Per-slot truthiness test (NOT a CONDITIONING input). When connected, this value decides whether the matching source_X is forwarded; if unconnected, source_X is tested against itself. | |
| pass_if_dopt | * | Per-slot truthiness test (NOT a CONDITIONING input). When connected, this value decides whether the matching source_X is forwarded; if unconnected, source_X is tested against itself. | |
| pass_if_eopt | * | Per-slot truthiness test (NOT a CONDITIONING input). When connected, this value decides whether the matching source_X is forwarded; if unconnected, source_X is tested against itself. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| output | * | — |
| matched | BOOLEAN | — |