From 7bb450edbfccd5c21dc5dbc1e7bf2f2ecc4c779c Mon Sep 17 00:00:00 2001 From: hugocasa Date: Thu, 26 Feb 2026 12:34:18 +0100 Subject: [PATCH] fix(backend): fix skip check crash when flow-level skip_expr triggers on first module with skip_if (#8111) When a flow has a flow-level `skip_expr` (or `no_flow_overlap`) and the first module has `skip_if` defined, the flow-level condition returns `UpdateFlow` before any identity job is created. The `UpdateFlow` path passes `Uuid::nil()` as `job_id_for_status`, causing `fetch_one` to fail with "no rows returned". - Change `fetch_one` to `fetch_optional` so a missing row returns false - Short-circuit the DB query with `stop_early && skip_if_stop_early` so both skip mechanisms (identity job check and early-stop skip flag) are considered - Also fixes the logical gap where a module with both `skip_if` and `stop_after_if` would only check the identity job, ignoring the early-stop skip signal Co-authored-by: Claude Opus 4.6 --- backend/windmill-worker/src/worker_flow.rs | 31 +++++++++++----------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/backend/windmill-worker/src/worker_flow.rs b/backend/windmill-worker/src/worker_flow.rs index bc630b3190..4d71bb1695 100644 --- a/backend/windmill-worker/src/worker_flow.rs +++ b/backend/windmill-worker/src/worker_flow.rs @@ -1099,21 +1099,22 @@ pub async fn update_flow_status_after_job_completion_internal( || (flow_jobs.is_some() && (skip_loop_failures || skip_seq_branch_failure))) && !(stop_early && stop_early_err_msg.is_some() && !skip_if_stop_early) { - let is_skipped = if current_module.as_ref().is_some_and(|m| m.skip_if.is_some()) - { - sqlx::query_scalar!( - "SELECT kind = 'identity' FROM v2_job WHERE id = $1", - job_id_for_status - ) - .fetch_one(db) - .await - .map_err(|e| { - Error::internal_err(format!("error during skip check: {e:#}")) - })? - .unwrap_or(false) - } else { - stop_early && skip_if_stop_early // Mark as skipped when stop_after_if with skip_if_stopped=true - }; + let is_skipped = (stop_early && skip_if_stop_early) + || if current_module.as_ref().is_some_and(|m| m.skip_if.is_some()) { + sqlx::query_scalar!( + "SELECT kind = 'identity' FROM v2_job WHERE id = $1", + job_id_for_status + ) + .fetch_optional(db) + .await + .map_err(|e| { + Error::internal_err(format!("error during skip check: {e:#}")) + })? + .flatten() + .unwrap_or(false) + } else { + false + }; success = true; ( true,