For Loop Close
Close the loop, carry the state, and know why it stopped
- iterator
- value_1
- value_2
- value_3
- value_4
- value_5
- value_6
- value_7
- value_8
- metadata
- value_1
- value_2
- value_3
- value_4
- value_5
- value_6
- value_7
- value_8
For Loop Open starts a loop; For Loop Close is what makes it a loop. It finishes one iteration and hands control back to the Open node for the next - and the values you route through it are the loop's memory. Anything you want to survive from one pass to the next, or to collect across all passes, travels through the Close node's slots.
The mental model is simple: the Open node's value_1 is "what slot 1 holds at the start of this pass." You read it inside the loop, change it, and wire the result into Close's value_1 - which becomes Open's value_1 on the next pass. The Close node is where each iteration's work lands and where the loop decides whether to keep going.
The inputs that matter
iterator- the WAS_LOOP wire from For Loop Open's iterator output. This is how Close knows which Open it belongs to, and it's the one connection you wire straight through and don't improvise with.value_1…value_8- each slot receives that iteration's value from the loop body and feeds the next pass. Any type, and a slot appears as you wire it.accumulate- the big one. Off (default), each value output holds only the last value the slot received. On, every value the slot held is collected: images, masks and latents get batched, other types go into a LIST. Turn this on when the loop's purpose is to gather - which is also whattotal_framesmode at the Open end counts on.stop- set it true and the loop ends after this iteration, whatever the iteration count or frame target asks for. It's read once the body has run, so it's an orderly early exit rather than a mid-frame abort - wire a condition node's result here and you get a loop with a real "break".
What comes out
metadata(DICT) - what the finished loop did, as one value: iterations completed, frames collected, why it stopped. Read it with Loop Metadata rather than guessing.value_1…value_8- each slot's result. Without accumulate, the last value it held; with it on, everything it held, batched where they batch.
Because it's an output node it runs even when nothing hangs off it, which is convenient - a Close node with accumulate on is doing collection work that downstream consumers will pick up, and you don't need to wire a dummy consumer just to force it to run.
Installing it and the classic mistakes
WAS Node Suite v3 - ComfyUI Manager → search WAS Node Suite v3, or clone into custom_nodes, restart. No weights, no dependencies.
Three mistakes account for nearly every "my loop does nothing / runs forever" report. Forgetting to route the value back through Close - if the body's result never reaches a Close slot, the loop sees no state and does the same thing each pass. Forgetting accumulate when you want all the values - off means only the last one survives, and total_frames mode quietly never reaches its target because nothing is being collected. Wiring the wrong Open - if your graph has two loops, the iterator wire is what keeps their Close nodes honest; cross them and the loops collapse into each other. Keep those three straight and the loop behaves exactly like the programming construct you're used to.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| iterator | WAS_LOOP | Identifies the loop and where it is up to; WAS_LOOP. Wired straight from For Loop Open's iterator output, and nothing else. | |
| accumulate | BOOLEAN | false | Collect every iteration's values; BOOLEAN. On, each value output carries everything that slot received, batched where images, masks or latents batch and a LIST where they do not. |
| value_1opt | COMFY_MATCHTYPE_V3 | Slot 1's value at the end of this iteration; any type. It goes back to For Loop Open's value_1 for the next one. | |
| value_2opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| value_3opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| value_4opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| value_5opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| value_6opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| value_7opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| value_8opt | COMFY_MATCHTYPE_V3 | Slot {n}'s value at the end of this iteration; any type. | |
| stopopt | BOOLEAN | false | Stop after this iteration; BOOLEAN. Read once the body has run, so it ends the loop early whatever iterations or total_frames ask for. |
Outputs (9)
| Name | Type | Description |
|---|---|---|
| metadata | DICT | What the finished loop did, as one value; DICT. Read it with Loop Metadata: iterations completed, frames collected, and why it stopped. |
| value_1 | COMFY_MATCHTYPE_V3 | Slot 1's result; any type. The last value it held, or every value it held once accumulate is on, batched where they batch and a LIST where they do not. |
| value_2 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |
| value_3 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |
| value_4 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |
| value_5 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |
| value_6 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |
| value_7 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |
| value_8 | COMFY_MATCHTYPE_V3 | Slot {n}'s result; any type. Every value it held while accumulate is on, otherwise the last one. |