docs/v3/concepts/states.mdx
States are rich objects that contain information about the status of a particular task run or flow run.
You can learn many things about a task or flow by examining its current state or the history of its states. For example, you might observe that a given run:
Scheduled to run for the third time in an hourLate because the associated worker process is not respondingScheduled to run, but later Cancelled via button in the UICached from a previous run instead of Running againCompleted after Running among its fellow task runsFailed because Claude left pydantic 1.x syntax in your codeCrashed because you Ctrl-C'd the processPrefect states have names and types.
A state's name is often, but not always, synonymous with its type. For example, a task run
that is running for the first time has a state with the name Running and the type RUNNING. However, if the task retries,
that same task run will have the name Retrying and the type RUNNING.
State types drive orchestration logic, whereas state names provide visual bookkeeping.
The full list of states and state types includes:
| Name | Type | Terminal? | Description |
|---|---|---|---|
Scheduled | SCHEDULED | No | The run will begin at a particular time in the future. |
Late | SCHEDULED | No | The run's scheduled start time has passed, but it has not transitioned to PENDING (15 seconds by default). |
<span class="no-wrap">AwaitingRetry</span> | SCHEDULED | No | The run did not complete successfully because of a code issue and had remaining retry attempts. |
<span class="no-wrap">AwaitingConcurrencySlot</span> | SCHEDULED | No | The run is waiting to occupy a concurrency slot prior to submission. |
Resuming | SCHEDULED | No | The run is scheduled to resume execution. |
Pending | PENDING | No | The run has been submitted to execute, but is waiting on necessary preconditions to be satisfied. |
Running | RUNNING | No | The run code is currently executing. |
Retrying | RUNNING | No | The run code is currently executing after previously not completing successfully. |
Paused | PAUSED | No | The run code has stopped executing until it receives manual approval to proceed. |
Suspended | PAUSED | No | The run code has stopped executing and the process has exited. |
Cancelling | CANCELLING | No | The infrastructure on which the code was running is being cleaned up. |
Cancelled | CANCELLED | Yes | The run did not complete because a user determined that it should not. |
Completed | COMPLETED | Yes | The run completed successfully. |
Cached | COMPLETED | Yes | The run result was loaded from a previously cached value. |
RolledBack | COMPLETED | Yes | The run completed successfully but the transaction rolled back and executed rollback hooks. |
Failed | FAILED | Yes | The run did not complete because of a code issue and had no remaining retry attempts. |
TimedOut | FAILED | Yes | The run did not complete because it exceeded its time out. |
Crashed | CRASHED | Yes | The run did not complete because of an infrastructure issue. |
When a flow run changes states, you can often tell if it is behaving normally or not. Here are some common state transitions and what they mean:
| From | To | Triggered By | Explanation | |
|---|---|---|---|---|
| ✅ | None | Scheduled | Manual run, automation, or schedule | A flow run has been created and scheduled for future execution. |
| ✅ | Scheduled | Pending | Worker | A worker is attempting to start the infrastructure for your flow run. |
| ⛔ | Scheduled | Late | Cloud or self-hosted server | Typically means that a worker did not pick up the run because 1) no workers are healthy, 2) workers are not polling the right work pool or work queue, or 3) workers are concurrency limited. |
| ✅ | Pending | Running | Worker | The infrastructure was provisioned and the flow is running |
| ⛔ | Pending | Crashed | Worker or runner | Something went wrong. Some possibilities are 1) the worker could have failed to create the infrastructure, 2) the code is not present in storage or the worker failed to authenticate, or 3) the code has missing or broken imports, or syntax errors. |
| ✅ | Running | Completed | Flow run | The flow completed successfully. |
| ⛔ | Running | Failed | Flow run | This usually means that your code raised an exception, check the flow run logs. |
| ⛔ | Running | Crashed | Worker or flow run | Probably not a raised exception in your code, but could be an infrastructure issue such as 1) an out of memory error, 2) an evicted pod, or 3) a timeout. |
The final state of a flow or task run depends on a number of factors; generally speaking there are three categories of terminal states:
COMPLETED: a run in any COMPLETED state did not encounter any errors or exceptions and returned successfullyFAILED: a run in any FAILED state encountered an error during execution, such as a raised exceptionCRASHED: a run in any CRASHED state was interrupted by an OS signal such as a KeyboardInterrupt or an unexpected SIGTERMThe flow of state transitions can be visualized here:
<Note> States are represented by their name, with boxes behind states clarifying their underlying type. Dotted lines lead to terminal states. </Note>%%{
init: {
'theme': 'neutral',
'flowchart': {
'curve' : 'linear',
'rankSpacing': 80,
'nodeSpacing': 70,
'width': 5
}
}
}%%
flowchart TD
%% Style definitions
classDef scheduled fill:#fcd14edb,stroke:#fcd14edb
classDef pending fill:#A99FADdb,stroke:#A99FAD
classDef running fill:#1860f2db,stroke:#1860f2db
classDef paused fill:#a99faddb,stroke:#a99faddb
classDef completed fill:#2ac769db,stroke:#2ac769db,stroke-width:2px
classDef failed fill:#fb4e4ef5,stroke:#fb4e4ef5,stroke-width:2px
classDef crashed fill:#f97316db,stroke:#f97316db,stroke-width:2px
classDef cancelled fill:#3d3d3da8,stroke:#3d3d3da8,stroke-width:2px
classDef awaiting_concurrency_slot fill:#ede7f6,stroke:#4527a0,stroke-width:2px
%% States
subgraph scheduled_type[Scheduled]
Scheduled[Scheduled]:::scheduled
Late[Late]:::scheduled
AwaitingConcurrencySlot[AwaitingConcurrencySlot]:::scheduled
end
Running[Running]:::running
Failed[Failed]:::failed
subgraph scheduled_type2[Scheduled]
AwaitingRetry[Awaiting Retry]:::scheduled
end
subgraph running_type[Running]
Retrying[Retrying]:::running
end
Pending[Pending]:::pending
Cancelling[Cancelling]:::cancelled
Cancelled[Cancelled]:::cancelled
Cached[Cached]:::completed
RolledBack[Rolled Back]:::completed
Crashed[Crashed]:::crashed
Paused[Paused]:::paused
Completed[Completed]:::completed
%% Connections
Scheduled --> |Scheduled start time passes without entering Pending| Late
Scheduled --> |Worker/Runner successfully submits run| Pending
Scheduled --> |Worker encounters concurrency limit| AwaitingConcurrencySlot
AwaitingConcurrencySlot --> Pending
Late --> Pending
Pending --> |Preconditions met| Running
Running -.-> |Success| Completed
%%problematic section:
Retrying -.-> |Success| Completed
Failed --> |Retries remaining| AwaitingRetry
AwaitingRetry --> |Retry attempt| Retrying
Retrying -.-> |Failure| Failed
Running -.-> |Error| Failed
Running -.-> |Infrastructure issue| Crashed
Running -.-> |Cache hit| Cached
Running -.-> |Transaction rollback| RolledBack
Running --> |User cancels| Cancelling
Running --> |Manual pause| Paused
Paused --> |Resume| Running
Cancelling -.-> |Cleanup complete| Cancelled
A task will be placed into a Completed state if it returns any Python object, with one exception:
if a task explicitly returns a Prefect Failed state, the task will be marked Failed.
from prefect import task, flow
from prefect.states import Completed, Failed
@task
def toggle_task(fail: bool):
if fail:
return Failed(message="I was instructed to fail.")
else:
return Completed(message="I was instructed to succeed.")
@flow
def example():
# this run will be set to a `Failed` state
state_one = toggle_task(fail=True)
# this run will be set to a `Completed` state
state_two = toggle_task(fail=False)
# similarly, the flow run will fail because we return a `Failed` state
return state_one, state_two
You can also access state objects directly within a flow through the return_state flag:
from prefect import flow, task
@task
def add_one(x):
return x + 1
@flow
def my_flow():
result = add_one(1)
assert isinstance(result, int) and result == 2
state = add_one(1, return_state=True)
assert state.is_completed() is True
assert state.result() == 2
import FinalFlowState from '/snippets/final-flow-state.mdx'
<FinalFlowState />State change hooks execute code in response to client side changes in flow or task run states, enabling you to define actions for specific state transitions in a workflow.
State hooks have the following signature:
from prefect import Task, Flow
from prefect.states import State
from prefect.client.schemas.objects import TaskRun, FlowRun
def my_task_state_hook(task: Task, run: TaskRun, state: State) -> None:
...
def my_flow_state_hook(flow: Flow, run: FlowRun, state: State) -> None:
...
State change hooks are versatile, allowing you to specify multiple state change hooks for the same state transition, or to use the same state change hook for different transitions.