Relationships
#3318 A forEach's iterations run in name order, not list order (operate-10 before operate-2)
Opened by skunk-ape · 10/12/2026· Shipped 10/12/2026
Problem
A forEach step's iterations run in the order of their expanded step names, not their place in the in list. With ten or more items, operate-10 through operate-19 run before operate-2. With concurrency: 1, a workflow that relies on list order (each call guarded on the one before it) skips every item from the tenth on.
Repro
Seen on swamp 20261008.143625.0-sha.ee36b409.
- Write a workflow with a step like
forEach: { item: op, in: ${{ <a list of 20 objects> }} },concurrency: 1, and amodel_methodtask that writes a record per item. - Give each item a guard that skips it unless the previous item's record exists.
- Run the workflow.
Expected: items 0 to 19 run in list order, and none is skipped.
Actual: the run log shows operate[10] through operate[19] before operate[2]. Items 10 and up are skipped by their guards, because the item before each has not run yet; only items 0 to 9 run.
Cause
TopologicalSortService.sort (src/domain/workflows/topological_sort_service.ts, around line 142) orders the nodes within one level by weight, then by name with localeCompare. The iterations a forEach expands to share a level and carry no weight for their index, so they sort as text: operate-1, operate-10, operate-11, ..., operate-2.
Workaround
stagecraft (swamp-club #3274) iterates zero-padded ids (0000, 0001, ...), whose names sort in list order, and looks up each item by id.
Suggested fix
Give each expanded iteration its list index as its weight (or sort iterations numerically by index), so a forEach runs in list order whatever the item count.
Shipped
Click a lifecycle step above to view its details.
Sign in to post a ripple.