{"record":{"id":"34727ab4730435ac","repo":"windmill-labs/windmill","slug":"parent-flow-job-not-found","errorCode":null,"errorMessage":"parent flow job not found","messagePattern":"parent flow job not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-api/src/jobs.rs","lineNumber":5398,"sourceCode":"    Ok((flow_info, result.is_flow_level, result.is_wac))\n}\n\nasync fn get_suspended_flow_info<'c>(\n    job_id: Uuid,\n    tx: &mut Transaction<'c, Postgres>,\n) -> error::Result<(FlowInfo, Uuid, bool)> {\n    let flow = sqlx::query_as!(\n            FlowInfo,\n            r#\"\n            SELECT j.id AS \"id!\", COALESCE(s.flow_status, s.workflow_as_code_status) as flow_status, q.suspend AS \"suspend!\", j.runnable_path as script_path, j.permissioned_as_email as email\n            FROM v2_job_queue q JOIN v2_job j USING (id) LEFT JOIN v2_job_status s USING (id)\n            WHERE j.id = $1\n            \"#,\n            job_id,\n        )\n        .fetch_optional(&mut **tx)\n        .await?\n        .ok_or_else(|| anyhow::anyhow!(\"parent flow job not found\"))?;\n\n    // Try to extract step job_id from FlowStatus modules (classic flow path)\n    let step_job_id = flow\n        .flow_status\n        .as_ref()\n        .and_then(|v| serde_json::from_value::<FlowStatus>(v.clone()).ok())\n        .and_then(|s| match s.modules.get(s.step as usize) {\n            Some(FlowStatusModule::WaitingForEvents { job, .. }) => Some(job.to_owned()),\n            _ => None,\n        });\n\n    if let Some(step_job_id) = step_job_id {\n        // Classic flow\n        Ok((flow, step_job_id, false))\n    } else if flow.suspend > 0 {\n        // WAC approval: no FlowStatus modules, but the job is suspended\n        // The flow_status here comes from COALESCE(flow_status, workflow_as_code_status),\n        // so for WAC it may contain approval_conditions from flow_status column","sourceCodeStart":5380,"sourceCodeEnd":5416,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-api/src/jobs.rs#L5380-L5416","documentation":"When resolving a step's parent flow inside a transaction, the flow job row (WHERE j.id = $1) is expected to exist; if fetch_optional returns None the lookup fails with this error. It indicates the parent flow job row is missing from the jobs table at resume time.","triggerScenarios":"Calling resume on a job id whose parent flow row no longer exists (deleted/purged); passing a malformed or non-existent job id; a race where the flow was removed between queue lookup and the transactional fetch.","commonSituations":"Stale approval links kept for days while cleanup removed the run; typos in job ids in scripts calling the resume API; retention jobs deleting finished runs referenced by old links.","solutions":["Confirm the parent flow job id exists (query the jobs table or runs UI)","Use the current run's job id from the flow run details, not an old one","Re-run the flow; the original run's data is gone","Check retention/cleanup settings if runs disappear too quickly"],"exampleFix":"// before\nawait api.resume(wId, staleJobId, payload);\n// after\nconst run = await api.getJob(wId, jobId); // 404 here before attempting resume\nif (run) await api.resume(wId, jobId, payload);","handlingStrategy":"validation","validationCode":"// verify the parent flow exists before resuming\nconst flow = await client.getJobRun(wId, parentFlowJobId).catch(() => null);\nif (!flow) throw new Error('parent flow gone: re-run the flow');","typeGuard":"function flowExists(run) {\n  return run !== null && run !== undefined && typeof run.id === 'string';\n}","tryCatchPattern":null,"preventionTips":["Keep retention windows longer than your approval SLA","Fetch the current run id from the UI/API instead of caching it","Watch for cleanup jobs deleting runs with pending approvals"],"tags":["flow","resume","not-found","database"],"backgroundTag":"record-not-found","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}