Bug summary
Description
Observed behavior
Tasks that are annotated with allow_failure runs if their direct upstream task is pending, if in turn it's upstream task has failed:
Tasks that don't specify allow_failure don't have this behavior and are correctly not started.
Expected behavior
Downstream tasks with allow_failure should not be executed if their parent is pending, in the same way as it works for tasks without allow_failure.
Reproduction
"""Minimal reproduction of allow_failure behavior with chained task failures."""
from prefect import allow_failure, flow, task
@task
def task_1_fails():
raise RuntimeError("Task 1 always fails")
@task
def task_2_depends_on_1():
print("Task 2 ran")
return "task_2_result"
@task
def task_3_allow_failure():
print("Task 3 ran (allow_failure) — THIS SHOULD NOT RUN if task 2 never ran")
return "task_3_result"
@task
def task_4_no_allow_failure():
print("Task 4 ran (no allow_failure) — this should not run")
return "task_4_result"
@flow
def repro_flow():
t1 = task_1_fails.submit()
t2 = task_2_depends_on_1.submit(wait_for=[t1])
t3 = task_3_allow_failure.submit(wait_for=[allow_failure(t2)])
t4 = task_4_no_allow_failure.submit(wait_for=[t2])
for label, future in [("t1", t1), ("t2", t2), ("t3", t3), ("t4", t4)]:
future.wait()
print(f"{label}: state={future.state.name}, type={future.state.type}")
if __name__ == "__main__":
repro_flow()
Run the above on a local Prefect Server. The output shows that task_3_allow_failure executes but task_4_no_allow_failure don't.
Console output
12:41:10.203 | INFO | prefect - Starting temporary server on http://127.0.0.1:8845
See https://docs.prefect.io/v3/concepts/server#how-to-guides for more information on running a dedicated Prefect server.
12:41:44.053 | INFO | Flow run 'antique-koala' - Beginning flow run 'antique-koala' for flow 'repro-flow'
12:41:44.114 | ERROR | Task run 'task_1_fails-18b' - Task run failed with exception: RuntimeError('Task 1 always fails')
Traceback (most recent call last):
File "/home/petlofg/git/analytics/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1021, in run_context
yield self
File "/home/petlofg/git/analytics/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1683, in run_task_sync
engine.call_task_fn(txn)
File "/home/petlofg/git/analytics/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1038, in call_task_fn
result = call_with_parameters(self.task.fn, parameters)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/petlofg/git/analytics/.venv/lib/python3.12/site-packages/prefect/utilities/callables/__init__.py", line 348, in call_with_parameters
return fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^
File "/home/petlofg/git/analytics/minimal_repro.py", line 8, in task_1_fails
raise RuntimeError("Task 1 always fails")
RuntimeError: Task 1 always fails
12:41:44.124 | ERROR | Task run 'task_1_fails-18b' - Finished in state Failed('Task run encountered an exception RuntimeError: Task 1 always fails')
12:41:44.127 | ERROR | Task run 'task_2_depends_on_1-08e' - Finished in state NotReady("Upstream task run '01a0335c-a28d-70b8-a2ed-ca6aadacbfc2' did not reach a 'COMPLETED' state.", type=PENDING)
t1: state=Failed, type=StateType.FAILED12:41:44.131 | ERROR | Task run 'task_4_no_allow_failure-a6a' - Finished in state NotReady("Upstream task run '01a0335c-a290-771a-8ae6-c311af7ed839' did not reach a 'COMPLETED' state.", type=PENDING)
t2: state=NotReady, type=StateType.PENDING
Task 3 ran (allow_failure) — THIS SHOULD NOT RUN if task 2 never ran
12:41:44.137 | INFO | Task run 'task_3_allow_failure-ca6' - Finished in state Completed()
t3: state=Completed, type=StateType.COMPLETED
t4: state=NotReady, type=StateType.PENDING
12:41:45.099 | INFO | Flow run 'antique-koala' - Finished in state Completed()
The output line Task 3 ran (allow_failure) — THIS SHOULD NOT RUN if task 2 never ran show that Task 3 ran even though Task 2 is pending/not ready. Note that no output is show for Task 4 which is correct.
Version info
Version: 3.8.3
API version: 0.8.4
Python version: 3.12.11
Git commit: d8f54b5c
Built: Thu, Aug 13, 2026 06:55 PM
OS/Arch: linux/x86_64
Profile: default
Server type: ephemeral
Pydantic version: 2.13.4
Server:
Database: sqlite
SQLite version: 3.47.1
Integrations:
prefect-azure: 0.4.12
prefect-docker: 0.7.3
prefect-shell: 0.3.6
prefect-snowflake: 0.28.8
prefect-dbt: 0.7.25
Additional context
We started noticing this behavior after upgrading from version 3.6.29 to 3.8.3. We've also tested this running on a self-hosted Prefect server which produces the same behavior. Could PR #21305 have caused this to start happening?
Bug summary
Description
Observed behavior
Tasks that are annotated with allow_failure runs if their direct upstream task is pending, if in turn it's upstream task has failed:
Tasks that don't specify allow_failure don't have this behavior and are correctly not started.
Expected behavior
Downstream tasks with allow_failure should not be executed if their parent is pending, in the same way as it works for tasks without allow_failure.
Reproduction
Run the above on a local Prefect Server. The output shows that task_3_allow_failure executes but task_4_no_allow_failure don't.
Console output
The output line Task 3 ran (allow_failure) — THIS SHOULD NOT RUN if task 2 never ran show that Task 3 ran even though Task 2 is pending/not ready. Note that no output is show for Task 4 which is correct.
Version info
Additional context
We started noticing this behavior after upgrading from version 3.6.29 to 3.8.3. We've also tested this running on a self-hosted Prefect server which produces the same behavior. Could PR #21305 have caused this to start happening?