windmill-labs/windmill · error

Timed out waiting for flow ${id} to complete

Error message

Timed out waiting for flow ${id} to complete

What it means

`wmill flow run` polls the queued flow job for completion and gives up after MAX_RETRIES (with 100ms sleeps), throwing this timeout. It means the flow did not reach a terminal state within the polling budget, not necessarily that the flow failed.

Source

Thrown at cli/src/commands/flow/flow.ts:595

      if (jobInfo.success === false) {
        process.exitCode = 1;
      }

      if (opts.silent) {
        console.log(JSON.stringify(jobInfo.result ?? {}));
      } else {
        log.info(JSON.stringify(jobInfo.result ?? {}, null, 2));
      }

      break;
    } catch {
      retries++;
      await new Promise((resolve) => setTimeout(resolve, 100));
    }
  }
  if (retries >= MAX_RETRIES) {
    throw new Error(`Timed out waiting for flow ${id} to complete`);
  }
}

async function preview(
  opts: GlobalOptions & {
    data?: string;
    silent: boolean;
    remote?: boolean;
    step?: string;
    tag?: string;
  } & SyncOptions,
  flowPath: string
) {
  if (opts.silent) {
    log.setSilent(true);
  }
  const useLocalPathScripts = !opts.remote;
  // Captured before the config read, which chdirs to the wmill.yaml root.

View on GitHub (pinned to e474e8803c)

Solutions

  1. Re-run with a longer wait or check the run in the web UI / `wmill flow status` to see if it eventually completed
  2. Check that workers are running and consuming from the right tag/queue
  3. Reduce flow runtime or split it; use schedules/webhooks instead of blocking CLI runs
  4. Check network stability between CLI and the instance

Example fix

// before
wmill flow run u/myuser/etl_flow
// after
wmill flow run u/myuser/etl_flow --async && wmill flow status <jobId>
Defensive patterns

Strategy: try-catch

Validate before calling

// Nothing to check before; instead pick --async for flows that may exceed the poll window
if (flowMayRunLong) useAsyncMode = true;

Try / catch

try {
  await client.flow.run(flowPath);
} catch (e) {
  if (String(e).startsWith('Timed out waiting for flow')) {
    // job may still be running: check status instead of re-queuing
    const status = await checkFlowRunStatus(jobId);
  }
}

Prevention

When it happens

Trigger: `wmill flow run <path>` where the flow runs longer than the retry window, or the poll loop cannot read the job (the catch branch also increments retries on transient API errors).

Common situations: Long-running flows (scheduled loads, heavy scripts); slow workers or no worker picking up the job; transient network/auth hiccups during polling consuming the retry budget.

Understand the failure class

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/b54ae0ad5d394fc4. Report an issue: GitHub.