Pipe Set List
Carry a whole list down the pipe without flattening it
- items
- pipe
- pipe
Pipe Set Any stores one value. This one stores the whole collection, under its own key, in a namespace of its own - and that separation is the reason both nodes exist.
The distinction it's protecting is the one that trips up more ComfyUI plumbing than any other: a list and a tensor batch are different things that look similar on the canvas. A batch of eight images is one value with an inner dimension; it goes through a sampler as one job. A list of eight images is eight values on one wire; it goes through a list node as eight jobs. Pipe Set Any refuses a list outright - it wants exactly one scalar. Pipe Set List is where the list goes, and it comes back out via Pipe Get List as a genuine Comfy list.
Inputs and output
key- STRING, default"items". Name it after the contents, since nothing in the graph will tell you what's inside later.items- any-type, and it takes the incoming list wholesale rather than requiring a single entry. An empty list is a legal field: stored as empty, read back as empty, no complaint.pipe- optional. Unwired, it starts a fresh pipe; wired, it adds the field to an existing one.
Output: pipe, the updated container.
Immutability, and why it's not just pedantry
Each call returns a new pipe rather than editing the one you passed in. If you branch one pipe down two paths and each path stores a different list field, both branches keep their own consistent version. With a shared mutable container, one branch's write would show up in the other, and the bug presents as "the getter returns the wrong list on one path only" - hours of your life looking at the wrong part of the graph.
There's a second slice of isolation inside: the stored list is kept as an internal copy, and readers get another copy. Editing the list downstream doesn't reach back through the pipe into other consumers. It's snapshots all the way down.
Where this earns its place
The header-region pattern is the main one: at the top of a canvas, build a pipe that carries your scalar settings and the lists your workflow iterates over - masks to process, images in a sequence, prompts per subject - then one wire down the side. Working nodes read scalars with Pipe Get Any and lists with Pipe Get List, and write back with Pipe To/Edit Any or another Set.
The second use is the one that saves the most keyboard time: it's a natural place to stage a list you're assembling. Keep the list in the pipe as it grows, then read it once at the end and hand the complete thing to whatever consumes a list. Pair it with the pack's accumulator nodes if you're building results up across iterations - the accumulator exists for lists that need to survive a loop, which is the one case a plain list-on-a-wire doesn't handle.
Beginner-level gotcha that isn't obvious: whichever getter you use has to match the setter. Scalar keys and list keys are separate fields even when the names are identical, and asking a list getter for a scalar key raises rather than guessing.
Install
Manager: search ComfyUI Utility Suite (publisher tom-m) → install → restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/tom-m-2020/ComfyUI-Utility-Suite
No models, nothing to download - the pack's only requirement is opencv-python-headless, which is for its mask nodes, not this one. It's written against ComfyUI's V3 node API and that's where the custom pipe socket type comes from, so on an old ComfyUI the pack installs and registers nothing.
Troubleshooting
A list went in and a scalar came out. You read it with Pipe Get Any instead of Pipe Get List. Different namespaces, and the node tells you so if you ask the wrong one.
"requires exactly one scalar execution value" isn't happening here and you expected it to. Right - that check belongs to Pipe Set Any. This node takes lists by design, including empty ones.
The list is missing items. The pipe stores what it was given. If the upstream list is shorter than you think, that's an upstream problem, and List / Batch Inspector is the pack's way to see whether you're holding a list, a batch, or neither.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| key | STRING | items | — |
| items | * | — | |
| pipeopt | UTILITY_ANY_PIPE | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| pipe | UTILITY_ANY_PIPE | — |