Optional Image (obvpm)
The img2img input you don't have to fill in
- input
- image
- present
If you've ever built one workflow that does both txt2img and img2img, you've met the problem this node solves. The VAE Encode at the front of the img2img path wants an IMAGE, and there isn't one when you're generating from scratch. So you either maintain two workflows, or you paste a throwaway image into a Load Image node and try to remember to ignore it.
Optional Image (obvpm) turns that hard requirement into a decision. Wire an image in and it passes straight through. Leave it unwired, and on_empty says what the rest of the graph should see - a dead path, or a polite None.
The mechanism, which is the whole story
on_empty has two values:
mute(default) - the node emits anExecutionBlockeron itsimageoutput. Every node downstream is skipped, silently. Nothing downstream can catch it; it's a kill, not a message.bypass- the node outputsNone. A downstream node whose input is optional reads that as "unconnected" and handles it. A downstream node whose input is required errors on it. Sobypassonly works when the consumer is written to tolerate absence.
Both modes affect the nodes after the gate only. Whatever fed the gate has already run - the gate can't un-run work. For the img2img case that's usually fine (the Load Image is cheap), but it's the distinction that makes the Lazy Switch family worth having.
Inputs and outputs
input- optional IMAGE. The thing to pass through; may be left unconnected.on_empty-muteorbypass.image- the input passed through, or blocked /Nonewhen empty.present- BOOLEAN, true when an input is connected, and live even in mute mode, because the blocker only sits on the image socket.
present is the reason this node is more than a guard clause. Convert a downstream KSampler's denoise widget to an input, and you can switch between "txt2img, denoise 1.0" and "img2img, denoise 0.6" based on whether an image exists - feed present through a Lazy Switch and only the chosen side executes. That's the difference between a workflow with two modes and two workflows.
Practical shapes
- One graph, two modes. Load Image → Optional Image → VAE Encode, with the txt2img path tapping in before the encode. Unplug the image and the img2img half dies on its own; plug one in and it lives.
- A reference image that's sometimes there. Reference-only ControlNet, IP-Adapter, a style reference - all of them take an IMAGE that isn't always wanted. Gate it, and
presentdrives the branch that switches reference conditioning in and out. - Multi-reference workflows. If the second and third references are optional, three gates and three
presentflags describe the state of your inputs in one place, which is much easier to read than three parallel image chains you toggle by hand.
Install
ComfyUI Manager → search the pack title comfyui-obvpm, or:
cd ComfyUI/custom_nodes
git clone https://github.com/chanon/comfyui-obvpm
Restart ComfyUI. It lands under obvpm/gates, and the node menu search for obvpm lists every node in the pack. No Python dependencies, no downloads - the pack's pyproject.toml declares none on purpose, since everything it imports already ships with ComfyUI. All class ids picked up the (obvpm) suffix in 0.2.0 to avoid colliding with another pack's ids; workflows from before that open fine, since the pack migrates the old names.
Where people get burned
Mute hides the failure, not the cause. A muted branch produces no error and no output - nodes simply don't appear in the run. If an image never reaches your VAE Encode, check whether a gate upstream is in mute before you go hunting in the sampler. Flipping it to bypass usually turns the mystery into a legible error.
Bypass into a required input throws. This is the single most common "the node is broken" report for any gate pack. It isn't broken: bypass means "I'm passing nothing", and a required socket has no way to represent nothing. If the consumer insists, the branch has to be muted. Or use a Lazy Switch, which answers the same question by not running the consumer at all.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| on_empty | COMBO | mute | What downstream sees when no input is connected: mute skips every downstream node, bypass outputs None. |
| inputopt | IMAGE | The value to pass through. May be left unconnected. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | The input passed through. When the input is empty: blocked (mute) or None (bypass). |
| present | BOOLEAN | True when an input is connected. Stays live even in mute mode. |