windmill-labs/windmill · error
unable to find the module
Error message
unable to find the module
What it means
After parsing flow_status, the code searches its modules list for the module whose job() equals the requested job; if none matches, it throws 'unable to find the module'. This means the flow status exists but does not reference the given step/job — the resume target is not a module of that flow run.
Source
Thrown at backend/windmill-api/src/jobs.rs:5520
// approvers are unaffected.
if let Some(authed) = authed.as_ref() {
require_job_within_run_scope(&db, authed, &w_id, &flow_id).await?;
}
let flow = GetQuery::new()
.without_logs()
.without_code()
.fetch(&db, &flow_id, &w_id)
.await?;
let flow_status = flow
.flow_status()
.ok_or_else(|| anyhow::anyhow!("unable to find the flow status in the flow job"))?;
let flow_module_status = flow_status
.modules
.iter()
.find(|p| p.job() == Some(job))
.ok_or_else(|| anyhow::anyhow!("unable to find the module"))?;
let trigger_email = match &flow {
Job::CompletedJob(job) => &job.email,
Job::QueuedJob(job) => &job.email,
};
conditionally_require_authed_user(
authed.clone(),
flow_status.approval_conditions.clone(),
trigger_email,
)?;
let approvers_from_status = match flow_module_status {
FlowStatusModule::Success { approvers, .. } => approvers.to_owned(),
_ => vec![],
};
let approvers = if approvers_from_status.is_empty() {
sqlx::query!(
r#"View on GitHub (pinned to e474e8803c)
Solutions
- Confirm the job id and flow id come from the same run
- Re-issue the approval/resume link from the correct run
- Re-run the flow if the old run's module state no longer matches
- Avoid hard-coding resume ids; derive them from the current run's flow status
Example fix
// before resume(wId, flowRunA_id, resumeIdFromRunB) // after resume(wId, flowRunB_id, resumeIdFromRunB)
Defensive patterns
Strategy: validation
Validate before calling
// make sure job and flow ids come from the same run
const run = await client.getJobRun(wId, flowJobId);
const module = (run.flow_status?.modules ?? []).find(m => m.job === stepJobId);
if (!module) throw new Error('step is not a module of this flow run'); Type guard
function stepBelongsToRun(flowStatus, stepJobId) {
return Boolean(flowStatus?.modules?.some(m => m.job === stepJobId));
} Prevention
- Derive resume ids from the same run object as the flow id
- Avoid caching resume links across reruns of a flow
- Tag run ids in logs so mismatches are easy to spot
When it happens
Trigger: Using a resume link/job id belonging to a different flow run than the flow_id supplied; a flow whose module status was overwritten by a later run of the same flow; approval step ids reused across reruns.
Common situations: Mixing ids from two concurrent runs of the same flow; approval link from run A applied to run B; flow edited and re-deployed so module layout no longer matches old statuses.
Related errors
- Invalid ${field}: id must be "${expectedId}"
- unable to find the flow status in the flow job
- not a flow
- Cannot push flow ${remotePath}: missing inline script file(s
- Cannot push flow ${remotePath}: step(s) reference non-worksp
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/cfcaae7e88ecf162.
Report an issue: GitHub.