Justin Anderson
07/15/2026, 3:49 PMMarvin
07/15/2026, 3:50 PMMarvin
07/15/2026, 3:51 PMpython
@flow
def my_flow():
try:
bad_task()
except Exception:
pass
return "done"
The task failed, but the flow did not. Since the exception was handled, the flow completed successfully.
2. You submitted tasks asynchronously and never waited on them
python
@flow
def my_flow():
future = bad_task.submit()
return "done"
Here the flow may finish before the task failure is surfaced to the flow.
3. You asked for task state/result explicitly but never used it to fail the flow
python
@flow
def my_flow():
state = bad_task(return_state=True)
return "done"
The task state may be Failed, but the flow still returned normally.
4. A task timed out, but the flow didn’t propagate that failure
A task timeout usually makes the task fail, but the flow only fails if that failure is raised/returned in a way the flow uses.
How to make the flow fail when a task fails or times out
Option A: let exceptions propagate
python
@flow
def my_flow():
bad_task()
If bad_task() raises and you don’t catch it, the flow fails.
Option B: wait on submitted futures and call .result()
python
@flow
def my_flow():
future = bad_task.submit()
future.result() # raises if task failed
That will surface the task failure to the flow.
Option C: return failed states
If you use return_state=True, inspect/return the state so Prefect can derive the flow state from it.
A useful mental model is:
- A failed task does not automatically imply a failed flow
- A failed flow means the flow itself ended in an error/failed state
If you want, I can also show:
- a minimal reproducible example of this behavior
- or a recommended pattern for making concurrent/submitted tasks fail the flow reliably
Relevant docs:
- States
- Flows
- Tasks