{"record":{"id":"80243cf58b242c77","repo":"windmill-labs/windmill","slug":"itered-cannot-be-empty","errorCode":null,"errorMessage":"itered cannot be empty","messagePattern":"itered cannot be empty","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/worker_flow.rs","lineNumber":5901,"sourceCode":"\n            if itered.is_empty() {\n                ForLoopStatus::EmptyIterator\n            } else if *parallel {\n                ForLoopStatus::ParallelIteration { itered_len: itered.len(), itered }\n            } else if let Some(first) = itered.first() {\n                let iter = Iter { index: 0 as i32, value: first.to_owned() };\n                ForLoopStatus::NextIteration(ForloopNextIteration {\n                    index: 0,\n                    itered_len: itered.len(),\n                    itered,\n                    flow_jobs: vec![],\n                    flow_jobs_success: Some(vec![]),\n                    flow_jobs_duration: Some(FlowJobsDuration::new(0)),\n                    new_args: iter,\n                    while_loop: false,\n                })\n            } else {\n                panic!(\"itered cannot be empty\")\n            }\n        }\n\n        FlowStatusModule::InProgress {\n            iterator: Some(FlowIterator { itered, index, .. }),\n            flow_jobs: Some(flow_jobs),\n            flow_jobs_success,\n            flow_jobs_duration,\n            ..\n        } if !*parallel => {\n            // Read itered from separate table or fallback to JSONB\n            let itered = read_itered_from_db(db, flow_job.id, itered).await?;\n\n            let itered_new = if itered.is_empty() {\n                // it's possible we need to re-compute the iterator Input Transforms here, in particular if the flow is being restarted inside the loop\n                let by_id = if let Some(x) = by_id {\n                    x\n                } else {","sourceCodeStart":5883,"sourceCodeEnd":5919,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/worker_flow.rs#L5883-L5919","documentation":"In the Windmill flow executor's while-loop/for-loop module handling, when a loop module is first entered and the iterator produced no items (`iter` is empty), the code panics instead of creating zero flow jobs. Windmill treats an empty iteration set as a modeling error for the loop step at this point, because the loop result structure (flow_jobs_success/duration, new_args) cannot be meaningfully constructed from nothing.","triggerScenarios":"A for-loop flow step whose input array/iterator expression evaluates to an empty list on the first pass (the `FlowStatusModule::InProgress` branch with no prior `itered` items), so `new_args: iter` would be an empty vec and the executor panics with 'itered cannot be empty'.","commonSituations":"A flow author wired a loop over a list that is empty at runtime (empty DB result, filtered array, optional input absent); a previous step returns `[]` on first run; skip_if or branching makes the source list empty only in some runs.","solutions":["Guard the loop input upstream: add a branch/preprocessor step that skips the loop module when the array is empty.","Check the loop step's iterator expression and fix it so it produces at least one item, or coerce empty to a sentinel (e.g. loop over `items.length ? items : [null]`).","If empty loops should be legal, patch worker_flow.rs to return a completed FlowStatus (zero jobs) instead of panicking when `iter` is empty.","Inspect the flow run logs to see which step produced the empty iterator and fix the producing step."],"exampleFix":"// before\n} else {\n    panic!(\"itered cannot be empty\")\n}\n// after\n} else {\n    // an empty iterator means the loop is trivially done\n    return Ok(FlowStatus::WaitingForCompletedJobs(FlowStatusModule::Success {\n        flow_jobs_success: Some(vec![]),\n        flow_jobs_duration: Some(FlowJobsDuration::new(0)),\n        new_args: serde_json::json!([]),\n        while_loop: false,\n    }));\n}","handlingStrategy":"validation","validationCode":"// before a for-loop flow step runs, ensure the iterator is non-empty\nconst items = args.my_list ?? [];\nif (!Array.isArray(items) || items.length === 0) {\n  throw new Error(\"loop input must be a non-empty array; skip the loop instead\");\n}","typeGuard":"function isNonEmptyArray(v: unknown): v is unknown[] {\n  return Array.isArray(v) && v.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Never wire a loop step directly to a list that can be empty; add a branch that bypasses the loop when the array is empty.","Test flows with empty upstream results (filtering, optional lookups) before deploying.","Coerce nullable upstream outputs to arrays with defaults at the producing step."],"tags":["rust","flow","loop","empty-iterator","panic"],"backgroundTag":"empty-iteration-input","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}