Nikhil Jain
04/23/2026, 11:14 PMMarvin
04/23/2026, 11:14 PMMarvin
04/23/2026, 11:16 PMpython
from prefect import flow
from prefect.states import Failed, Cancelled
@flow
def my_flow(should_fail: bool):
if should_fail:
return Failed(message="Validation failed")
return "ok"
Then:
python
state = my_flow(True, return_state=True)
print(state.type) # FAILED
A few useful notes:
* return Failed(...) marks the flow run as failed without throwing Python errors
* You can also return Cancelled(...), Paused(...), etc.
* If you don’t use return_state=True, Prefect will normally give you the flow result, not the state object
A common pattern is:
python
from prefect import flow
from prefect.states import Failed, Completed
@flow
def check_inputs(x):
if x < 0:
return Failed(message="x must be non-negative")
return Completed(message="Inputs look good")
If you want, you can also attach data:
python
from prefect.states import Failed
return Failed(
message="Business rule failed",
data={"reason": "customer inactive"}
)
One caveat:
Returning a state object is supported, but it’s best used when you intentionally want to control the final run state. If you just want to stop early but still be considered successful, return a normal value instead.
Relevant docs/source-backed behavior:
* Prefect flow concepts: https://docs.prefect.io/
* Deployment/flow patterns in Prefect 3.x: https://docs.prefect.io/v3/
If you want, I can also show the difference between:
1. raising an exception,
2. returning Failed(...), and
3. handling a failed task while keeping the flow successful.Nikhil Jain
04/23/2026, 11:19 PMFailed state. If I return the Failed() object like you described above, will it trigger the alert via the automation? My goal in asking you this question was to find a way to mark a flow as failed without sending us an alert @MarvinMarvin
04/23/2026, 11:19 PMMarvin
04/23/2026, 11:20 PMFailed state, an automation that triggers when a flow enters Failed should still fire, even if you got there by return Failed(...) instead of raising an exception.
So for your goal:
return Failed(...) is not a good way to suppress a failure alert.
From Prefect’s perspective, the run is still failed. The automation reacts to the state transition, not to whether Python raised an error.
If you want the run to be unsuccessful in a business sense but not trigger a Failed automation, you generally have a few options:
1. Return a successful state/value and encode the business outcome in the result/logs
* e.g. return "no data to process" or a structured object like {"status": "rejected"}
* the flow run will be Completed, so the Failed automation will not fire
2. Use a different non-failure state if it matches your semantics
* Cancelled or Paused are different states, so a Failed automation would not match them
* but only use these if they accurately describe what happened
3. Change the automation logic
* If some failures are expected, the cleanest solution is often to refine the automation so it alerts only on the failures you care about
* for example, based on tags, deployment, work pool, or other available event criteria in the automation UI
For your use case, the most common pattern is:
Keep the flow in Completed
Log clearly that the business outcome was not successful
Optionally return structured metadata describing the outcome
Example:
python
from prefect import flow, get_run_logger
@flow
def my_flow(records):
logger = get_run_logger()
if not records:
logger.warning("Flow completed without processing records")
return {
"status": "no-op",
"reason": "No records found"
}
# normal work here
return {
"status": "processed",
"count": len(records)
}
That will not trigger a Failed-state automation.
If you'd like, I can help you design a pattern for business failure vs orchestration failure in Prefect so only true operational problems send alerts.