Hui Wu
05/19/2026, 6:38 AMMarvin
05/19/2026, 6:38 AMMarvin
05/19/2026, 6:39 AMCancelledError when the task is being cancelled cooperatively inside the Python process.
You get SIGKILL only when Prefect is cancelling an external process and that process does not exit after a grace period.
So the distinction is mostly:
* same Python process → CancelledError
* separate process / worker infrastructure → SIGTERM first, then SIGKILL if it refuses to stop
### When Prefect uses CancelledError
This is the normal case for tasks executed by the task runner in the same process as the flow:
* async tasks
* sync tasks running in-process
* timeout/cancellation handled cooperatively by the engine
In these cases, Prefect raises cancellation exceptions in Python rather than killing the process.
### When Prefect uses SIGKILL
This happens when the flow run is executing in a separate OS process and Prefect is trying to stop that process.
Typical sequence:
SIGTERM -> wait for grace period -> SIGKILL
So Prefect will send SIGKILL when:
* the run is in a subprocess / worker-managed process
* Prefect has already asked it to stop
* the process does not exit within the grace period
SIGKILL is a last resort. It means the process ignored or did not respond to graceful shutdown.
### Important nuance
Usually Prefect sends SIGTERM first, not SIGKILL immediately.
That gives the process a chance to:
* handle cancellation
* run cleanup
* exit cleanly
If it still hangs, then Prefect force-kills it with SIGKILL.
### Examples of when SIGKILL is more likely
If your task/flow process is stuck in something like:
* blocking native code
* hung network call
* deadlock
* uninterruptible subprocess behavior
then it may never respond cleanly to cancellation, so Prefect eventually kills the whole process.
### Practical rule
If you are asking:
“Why did my task not getThat usually means the task was *not being cancelled in-process*; instead, the worker/infrastructure process running the flow was terminated. ### One more subtlety Prefect generally cancels at the flow run process level in worker/infrastructure execution. So if that process gets SIGKILL, your task code does not get a chance to catch, but instead the process died?”CancelledError
CancelledError at all.
If you want, I can also give you a matrix by execution mode like:
* local flow + ThreadPool task runner
* async flow/task
* subprocess worker
* Docker / Kubernetes worker
and show exactly which ones get CancelledError vs signal termination.