windmill-labs/windmill · error · Error
Job ${jobId} was not successful: ${JSON.stringify(error)}
Error message
Job ${jobId} was not successful: ${JSON.stringify(error)} What it means
Thrown by waitJob when the polled job completed with success=false. The job's own `error` field is JSON-serialized into the message, so the text carries the underlying run failure (script exception, invalid args, worker error) — this is the client surfacing a failed execution, not a client-side fault.
Source
Thrown at typescript-client/client.ts:306
while (true) {
// Implement your HTTP request logic here to get job result
const resultRes = await getResultMaybe(jobId);
const started = resultRes.started;
const completed = resultRes.completed;
const success = resultRes.success;
if (!started && verbose) {
console.info(`job ${jobId} has not started yet`);
}
if (completed) {
const result = resultRes.result;
if (success) {
return result;
} else {
const error = result.error;
throw new Error(
`Job ${jobId} was not successful: ${JSON.stringify(error)}`
);
}
}
if (verbose) {
console.info(`sleeping 0.5 seconds for jobId: ${jobId}`);
}
await new Promise((resolve) => setTimeout(resolve, 500));
}
}
/**
* Get the result of a completed job
* @param jobId - ID of the completed job
* @returns Job result
*/View on GitHub (pinned to e474e8803c)
Solutions
- Read the JSON error payload in the message to find the actual failure cause
- Fix the bug in the script/flow that made the run fail
- Wrap the call in try/catch if failure is expected and handle the error object
- Re-run with verbose logging to see intermediate job state
Example fix
// before
const result = await client.runScriptByPath('etl/job', args)
// after
try {
const result = await client.runScriptByPath('etl/job', args)
} catch (e) {
console.error('job failed:', e.message) // includes job id + server error JSON
} Defensive patterns
Strategy: try-catch
Try / catch
try {
const result = await client.runScriptByPath(path, args)
} catch (e) {
if (String(e.message).startsWith('Job ') && e.message.includes('was not successful')) {
const payload = JSON.parse(e.message.slice(e.message.indexOf('{')))
console.error('Job failed on server:', payload)
} else throw e
} Prevention
- Test scripts/flows in the UI before automating them via the client
- Pass verbose: true while debugging job failures
- Validate inputs against the script's schema before running
When it happens
Trigger: Calling runScript*/runFlow* (which await waitJob) when the underlying script/flow execution fails — e.g. an uncaught exception in the script, a failed flow step, or a denied/precondition failure.
Common situations: Bugs in the executed script or flow; missing resource/variable at runtime; invalid inputs causing the run to error; flow routing to a failure branch.
Related errors
- ApiError with mapped HTTP status message (e.g. "Not Found",
- Generic Error: status: ${errorStatus}; status text: ${errorS
- path and hash_ are mutually exclusive
- path or hash_ must be provided
- Failed to poll dependencies job ${jobId}: ${e?.message ?? e}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/32573116745e922f.
Report an issue: GitHub.