ND Upscale Result (internal)
The node you should never add, and shouldn't panic about
- image
You won't find this one in the node search, and if it ever shows up in your workflow you didn't put it there. It's the little end-cap the Variant Preview Selector bolts onto your upscale branch at the moment you click its Upscale button.
What it is
An output node that saves one image and reports it back to the selector. That's it. Its whole reason for existing is a gap in the upscale hand-off: the selector doesn't upscale anything - you build the upscale branch yourself, with whatever nodes you like, third-party included - so nothing in that branch is guaranteed to be an output node. Without a sink, ComfyUI would evaluate the branch and throw the result away.
So when you hit Upscale, the frontend builds the prompt it's about to send and injects this node into it, wired to whatever you plugged into the selector's image field. It only exists in that queued prompt. It never appears on your canvas.
Its inputs
Four, all written by the frontend - this is not a node you configure:
image(IMAGE) - the upscale branch's output. It saves the first image only (image[:1]), because a "the upscaled result" that's secretly eight images is not what the button promised.target_id(STRING, default empty) - which selector to report back to. The frontend uses the selector's prompt id, so the right node gets the thumbnail.filename_prefix(STRING, defaultND_Image) - copied from the selector's own file-name setting.suffix(STRING, defaultupscaled) - appended after the prefix, giving youND_Image_upscaled_00001_.png, numbered exactly like the stock Save Image node. It also embeds workflow metadata the same way, unless ComfyUI is running with--disable-metadata.
No outputs. It's a terminal.
The mechanism around it, briefly
Knowing where the sink comes from explains the behaviour that surprises people. The Upscale click doesn't queue your workflow the normal way - it builds the prompt, strips the feedback link (the wire from the upscale result back into the selector, which would otherwise be a cycle), sets upscale_trigger = true on the selector, restores the seeds and other control values from the last run so the sampling comes from cache, re-routes the selector's outputs through the internal ND Variant Values helper, and sends that straight to the API. The sink is added in the same pass.
Net effect for you: the upscale run reuses the generation you already made, doesn't advance your randomize-on-run seeds, and still gives you a saved file. That's a genuinely thoughtful bit of design and it's all invisible.
When you actually encounter it
In an exported API prompt. Exports show the resolved prompt, so nd_sink_<id> will be sitting there as a node. Harmless, and the reason a .json workflow exported while a selector is around looks bigger than the canvas version.
In an error message when the node class isn't registered - e.g. an API prompt from someone else's machine run against an install without the pack. Then the sink is a missing node and the prompt fails validation. The fix is installing Neural Dreamer Nodes, not deleting nodes from the JSON.
In a workflow someone shared after clicking Upscale. Occasionally the helper survives a copy. You can leave it: it saves an image and does nothing else. If it's sitting there with nothing plugged in, delete it.
Install
You get it with the pack (v1.1.0, MIT). Clone and restart:
cd ComfyUI/custom_nodes
git clone https://github.com/neural-dreamer/ComfyUI-NeuralDreamer-Nodes.git
Or install "Neural Dreamer Nodes" via ComfyUI Manager. No Python dependencies - the pyproject.toml has an empty dependency list - and no model files.
Then refresh the tab, because the node is created by frontend code; a stale tab can fail to register it and you'll get "missing node type" on an upscale you definitely should be able to do.
Common issues
"The node is not part of the prompt (it may be bypassed or muted)." That toast comes from the selector, not this node: the selector itself is bypassed, muted, or sitting in a muted group, so there's no prompt id to attach a sink to. Un-mute it.
The upscaled file is saved twice. If your branch also ends in a Save Image, both write. The sink isn't a substitute for your own output node - it's there to catch the case where you have none.
My upscale lost its seed. Check whether anything upstream of the selector really randomizes on every run. The Upscale path restores control values from the last Run precisely so the sampling hits cache; a node that forces a re-run (any IS_CHANGED that always reports changed) will defeat that and you'll generate fresh instead of upscaling the image you were looking at.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| target_id | STRING | — | |
| filename_prefix | STRING | ND_Image | — |
| suffix | STRING | upscaled | — |
Outputs (0)
No outputs