windmill-labs/windmill · error
errorMsg ?? 'Job failed'
Error message
errorMsg ?? 'Job failed'
What it means
pollJobResult polls a script/job until completion and throws when the finished job's result contains an error, preferring the job's own error.message and falling back to 'Job failed'. It converts an async job failure into a rejected promise for the caller.
Source
Thrown at frontend/src/lib/components/jobs/utils.ts:112
await new Promise((resolve) =>
setTimeout(resolve, attempts ? 500 * attempts : pollDelayMs(polls++))
)
const job = await JobService.getCompletedJobResultMaybe({
id: uuid,
workspace
})
if (job.success) {
if (withJobData) {
return { job: { id: uuid }, result: job.result }
} else {
return job.result as any
}
} else if (job.completed) {
attempts = maxRetries
let errorMsg: string | undefined = (job?.result as any)?.error?.message
if (typeof errorMsg !== 'string') errorMsg = undefined
console.error('JOB FAILED', job.result)
throw new Error(errorMsg ?? 'Job failed')
} else if (failIfNoWorkerForTag && Date.now() >= noWorkerProbeAt) {
const tag = await missingWorkerTagOfQueuedJob(workspace, uuid)
noWorkerProbeAt = Date.now() + NO_WORKER_PROBE_INTERVAL_MS
unservedProbes = tag ? unservedProbes + 1 : 0
if (tag && unservedProbes >= NO_WORKER_CONFIRMATIONS) {
if (!reportedNoWorker) {
reportedNoWorker = true
onNoWorkerForTag?.(tag)
}
// Reads give up the wait but leave the job queued: cancelling one would
// remove the very backlog the autoscaler scales up on, so a group coming
// back from zero (300s cooldown) would never recover. Writes keep
// waiting instead (see `sideEffecting`).
if (!sideEffecting) throw new NoWorkerForTagError(tag)
}
}
} catch (e) {
if (e instanceof NoWorkerForTagError) {View on GitHub (pinned to e474e8803c)
Solutions
- Read the thrown message (job result error.message) and fix the script's root cause; full result is logged via console.error('JOB FAILED', ...).
- Open the run in the UI run history to see the stack trace and logs.
- If the message is the generic 'Job failed', inspect the run logs server-side for the real exception.
- Add retry/validation in the script for transient inputs, and handle the rejection at the call site.
Example fix
// before
await pollJobResult(ws, uuid)
// after
try { await pollJobResult(ws, uuid) } catch (e) { console.error('run failed:', e.message) } Defensive patterns
Strategy: try-catch
Type guard
function jobHasErrorMessage(job) { return typeof (job?.result as any)?.error?.message === 'string' } Try / catch
try { const result = await pollJobResult(ws, uuid) } catch (e) { showError(e.message); openRunLogs(uuid) } Prevention
- Check run logs in the UI when the message is the generic 'Job failed'
- Add input validation inside scripts to fail fast with descriptive messages
- Set retries/maxRetries appropriately for transient failures
When it happens
Trigger: A polled job ends with status failure/completed-with-error: run failed (unhandled exception in the script), or the script returned { error: { message } } in its result.
Common situations: Script code raised (bad input, missing dependency, timeout); the job was denied/queued into failure by worker errors; API responses where result.error.message is absent so only the generic message appears.
Related errors
- ${timeoutMessage}
- Job ${jobId} was not successful: ${JSON.stringify(error)}
- Failed to re-run job ${id}.
- Completed jobs file must contain an array of jobs
- Failed to push completed jobs: ${e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/f0744f6ae0ee154b.
Report an issue: GitHub.