Custom Gate
Flip a branch without letting the mask and the image get separated
- in1
- in2
- else1
- else2
- out1
- out2
ComfyUI is 70% plumbing. The nodes that get written about touch pixels; the larger population just moves things around. Custom Gate is squarely in the second camp, and it solves a specific, irritating problem: it switches an IMAGE and a MASK together, as a pair, in one node.
If you've ever wired two separate switch nodes to flip an inpaint branch, you already know why the pairing matters. Wire them separately and you get the image from branch A, the mask from branch B - which does not error. It composites the wrong region and you spend the evening blaming the prompt.
What it does
enabled is a boolean. True sends in1 and in2 to the outputs. False sends else1 and else2.
def route(self, enabled, in1, in2, else1=None, else2=None):
if enabled:
return (in1, in2)
return (else1, else2)
Required inputs are enabled (BOOLEAN, default on), in1 (IMAGE) and in2 (MASK). else1 (IMAGE) and else2 (MASK) are optional - that second branch is the one you flip to. Outputs are out1 (IMAGE) and out2 (MASK), in that order, and they stay locked together.
Where it earns its place
The two-branch workflow is a common shape: a plain pass versus an inpaint pass, a raw frame versus a relit one, a base image versus a detailer output. Whoever built the graph keeps a "clean" branch wired next to the "processed" one and flips between them without rebuilding anything. Once a mask is involved, the switch has to move both or it's a footgun.
Know which kind of switch you're looking at - "switch" means two different things here. rgthree's Any Switch is a fallback switch: no selector, it passes the first input that isn't null. Custom Gate is the A/B shape: you decide, with a boolean.
And because enabled is a widget, right-click → Convert widget to input lets you drive it from a boolean primitive or another node's output - handy when one workflow runs two passes with different settings.
The trap: what "else" is when you leave it empty
Unconnected optional inputs arrive at the function as None - that's a ComfyUI engine convention, not this pack's invention. So if else1 and else2 are both unwired and you flip enabled off, the node outputs literal None for both, and the next node in line either handles it or dies on a NoneType error.
That's deliberate, and it's the useful half of the design if the downstream input is genuinely optional - you've built the "populate the socket with nothing" pattern, and a node written to treat None as "no mask supplied" will skip that stage cleanly. It's a hard error if the input is required. And no, an empty image is not a black mask: None means nothing was supplied, a zero mask means "selected nowhere". Nodes that respect the distinction do the right thing; the ones that don't make it obvious fast.
Two more things worth knowing before you rely on this:
- Both branches still compute. The node reads its inputs eagerly, so flipping the switch changes which result you get, not which work runs - the branch you turned off still executes each run. If saving sampling time is the goal, you want a lazy switch instead.
- It's per-run, not per-image. The boolean is one value for the whole execution; it can't route different images in a batch to different branches.
Install
One of five nodes in Mochorong (author mochorongo, MIT, v1.0.1, no reputation of its own - this is a utility pack, not a framework). ComfyUI Manager, search Mochorong; or:
cd ComfyUI/custom_nodes
git clone https://github.com/mochorongo/Mochorong
Restart ComfyUI. The README's registry form is comfy node install comfyui-mochorong.
No dependencies to install - no requirements.txt, no models to download. It uses torch, numpy, PIL and folder_paths, all of which ship with ComfyUI, and lists Python 3.10 as the floor. You'll find the node under the Mochorong category; if it isn't there, the number one cause is a nested clone folder, so check that the .py files sit directly in custom_nodes/Mochorong/.
Troubleshooting the real cases
- "
NoneTypeobject has no attribute ..." right after you flip the gate - you turned it off with nothing wired toelse1/else2, and the consumer wanted a real image. Wire the fallback, or route into a node whose image input is optional. - The mask is wrong but nothing errored. That's the failure this node exists to prevent - check you're not still running two independent switches somewhere else in the graph.
- The gate looks stuck. Bypass state and the widget look similar in the editor; make sure you're toggling
enabledand not the node's mode.
Sources: Mochorong custom_gate.py and README (read 2026-09-14); docs/knowledge/comfyui-node-plumbing.md for the A/B versus fallback switch taxonomy, optional-inputs-are-None, and the convert-widget-to-input mechanic; kg/entities/rgthree-comfy.json and docs/knowledge/comfyui-ecosystem.md for the switch/plumbing tool landscape and rgthree's standing.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| enabled | BOOLEAN | true | — |
| in1 | IMAGE | — | |
| in2 | MASK | — | |
| else1opt | IMAGE | — | |
| else2opt | MASK | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| out1 | IMAGE | — |
| out2 | MASK | — |