windmill-labs/windmill · error · Exception
Job {job_id} was not successful: {str(error)}
Error message
Job {job_id} was not successful: {str(error)} What it means
When a waited job completes unsuccessfully (status failure), wait_job extracts result['error'] and raises 'Job {job_id} was not successful: {error}'. This surfaces the script's own runtime failure captured by the Windmill server.
Source
Thrown at python-client/wmill/wmill/client.py:434
started = result_res["started"]
completed = result_res["completed"]
success = result_res["success"]
if not started and verbose:
logger.info(f"job {job_id} has not started yet")
if cleanup and completed:
atexit.unregister(cancel_job)
if completed:
result = result_res["result"]
if success:
if result is None and assert_result_is_not_none:
raise Exception("Result was none")
return result
else:
error = result["error"]
raise Exception(f"Job {job_id} was not successful: {str(error)}")
if timeout and ((time.time() - start_time) > timeout):
msg = "reached timeout"
logger.warning(msg)
self.post(
f"/w/{self.workspace}/jobs_u/queue/cancel/{job_id}",
json={"reason": msg},
)
raise TimeoutError(msg)
if verbose:
logger.info(f"sleeping 0.5 seconds for {job_id = }")
time.sleep(0.5)
def cancel_job(self, job_id: str, reason: str = None) -> str:
"""Cancel a specific job by ID.
Args:View on GitHub (pinned to e474e8803c)
Solutions
- Read the embedded error text and open the job run in the Windmill UI (runs page) for the full stack trace.
- Fix the underlying script error indicated in the message (imports, arguments, resource access).
- Wrap wait_job in try/except if the caller should continue when the job fails.
- Optionally set allowed_failure on the script/step so Windmill records success despite the error.
Example fix
// before
result = client.wait_job(job_id) # raises on failure
// after
try:
result = client.wait_job(job_id)
except Exception as e:
logger.error(f'job failed: {e}')
handle_failure(e) Defensive patterns
Strategy: try-catch
Try / catch
try:
result = client.wait_job(job_id)
except Exception as e:
if str(e).startswith('Job ') and 'was not successful' in str(e):
job_id = str(e).split()[1]
details = client.get_job(job_id)
logger.error('job failed: %s — see %s', e, details.get('logs'))
else:
raise Prevention
- Test the script in isolation in the Windmill UI before orchestrating it from Python.
- Check job logs on the runs page for the underlying stack trace.
- Use allowed_failure on optional steps so expected errors don't fail the job.
- Pin script dependencies to avoid environment drift causing runtime failures.
When it happens
Trigger: wait_job() on a job whose script/flow raised an unhandled exception, exited non-zero, was canceled, or failed a step inside a flow; job reached failure state while the client was polling.
Common situations: Script bug (uncaught exception in the executed code); missing dependency in the script environment; failure of a resource/credential lookup at runtime; a downstream flow step failing.
Related errors
- result is None for {job_id = }
- path or hash_ must be provided
- Result was none
- reached timeout
- could not read the run of job ${id}: ${res.status} ${await r
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/5c90b93894c06263.
Report an issue: GitHub.