windmill-labs/windmill · error · Error
${timeoutMessage}
Error message
${timeoutMessage} What it means
runWithProgress enforces a timeout (default 60s, configurable via JobOptions.timeout). When tryEvery's deadline expires, the timeoutCode callback first attempts to cancel the queued job server-side (JobService.cancelQueuedJob), reports onProgress({status:'failure'}), and throws Error(timeoutMessage), by default `Job timed out after Ns`.
Source
Thrown at frontend/src/lib/services/JobManager.ts:124
onProgress?.(status)
finalResult = jobResult.result as T
return jobResult.result as T
},
timeoutCode: async () => {
try {
await JobService.cancelQueuedJob({
workspace,
id: jobId,
requestBody: { reason: timeoutMessage }
})
} catch (err) {
console.error('Failed to cancel job:', err)
}
onProgress?.({ status: 'failure', error: timeoutMessage })
throw new Error(timeoutMessage)
},
interval,
timeout
})
return finalResult as T
} finally {
this.activeJobs.delete(jobId)
}
}
cancel(jobId: string) {
const entry = this.activeJobs.get(jobId)
if (entry) {
entry.controller.abort()
this.activeJobs.delete(jobId)
}
}View on GitHub (pinned to e474e8803c)
Solutions
- Increase the timeout option passed to runWithProgress to exceed the job's expected duration
- Investigate why the job is slow (worker availability, job logs in the Windmill UI)
- Reduce the job's work or split it into smaller steps
- Handle the timeout error in the caller and offer retry/extend UI
Example fix
// before
const result = await jobManager.runWithProgress(runJob, { workspace, onProgress }) // default 60s timeout
// after
const result = await jobManager.runWithProgress(runJob, {
workspace,
onProgress,
timeout: 300000, // 5 min
timeoutMessage: 'Generation timed out after 5 minutes'
}) Defensive patterns
Strategy: retry
Validate before calling
// size the timeout to the job before starting
const expectedMs = estimateJobDuration(jobKind)
if (expectedMs > (options.timeout ?? 60000)) {
options.timeout = expectedMs * 2
} Try / catch
try {
const result = await jobManager.runWithProgress(runJob, { ...opts, timeout: 300000 })
} catch (err) {
if (err instanceof Error && err.message.startsWith('Job timed out')) {
onTimeout(err.message) // offer retry or poll the job manually via JobService
return
}
throw err
} Prevention
- Set timeout generously above the job's worst-case duration
- Surface onProgress failure states so users see slowness before the hard timeout
- Check worker capacity/queue depth when timeouts cluster
- Split long flows into smaller steps instead of one long job
When it happens
Trigger: The Windmill job (script/flow/AI generation) takes longer than options.timeout to complete while getCompletedJob keeps returning a non-completed job; interval polling never sees success before the deadline.
Common situations: Long-running flows or heavy scripts polled from the UI with the default 60s timeout; slow worker queues under load; AI generation jobs exceeding the default; passing a timeout smaller than the job's realistic duration.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Timed out after ${Math.round(CASCADE_JOB_TIMEOUT_MS / 60000)
- Timed out waiting for job ${jobId}
- reached timeout
- Job ${jobId} was not successful: ${JSON.stringify(error)}
- Timed out waiting for flow ${id} to complete
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/26fe60bb61b54d36.
Report an issue: GitHub.