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

  1. Read the embedded error text and open the job run in the Windmill UI (runs page) for the full stack trace.
  2. Fix the underlying script error indicated in the message (imports, arguments, resource access).
  3. Wrap wait_job in try/except if the caller should continue when the job fails.
  4. 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

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


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