Celery WorkerLostError: Worker exited prematurely (tested)
WorkerLostError: Worker exited prematurely: signal 9 (SIGKILL) means the pool process running the task was killed from outside, usually by the out-of-memory killer. exitcode N means code in the task process called exit. Neither can be caught inside the task.
WorkerLostError: Worker exited prematurely means the prefork child process running your task died before it could report a result. Python code did not raise it: the process itself went away, so try/except inside the task cannot catch it. The text after "exited prematurely" tells you how it died.
1. exitcode vs signal 9 (SIGKILL)
$ cat tasks.py
import os, signal
from celery import Celery
app = Celery("tasks", broker="redis://127.0.0.1:8964/0", backend="redis://127.0.0.1:8964/1")
@app.task
def crash():
os._exit(1) # like a C extension calling exit()
@app.task
def killed():
os.kill(os.getpid(), signal.SIGKILL) # what the Linux OOM killer does
$ celery -A tasks worker -c 1 --loglevel=INFO > worker.log 2>&1 &
$ cat run.py
from tasks import crash, killed
for t in (crash, killed):
try:
print(t.name, "->", t.delay().get(timeout=20))
except Exception as e:
print(t.name, "->", type(e).__name__, e)
$ timeout 60 python run.py
tasks.crash -> WorkerLostError Worker exited prematurely: exitcode 1 Job: 0.
tasks.killed -> WorkerLostError Worker exited prematurely: signal 9 (SIGKILL) Job: 1.
The worker log names the dead process:
$ grep -E "ERROR|WARNING|succeeded" worker.log | cut -c1-200
[2026-10-23 10:59:52,141: ERROR/MainProcess] Process 'ForkPoolWorker-1' pid:3012915 exited with 'exitcode 1'
[2026-10-23 10:59:52,159: ERROR/MainProcess] Task handler raised error: WorkerLostError('Worker exited prematurely: exitcode 1 Job: 0.')
[2026-10-23 10:59:52,185: ERROR/MainProcess] Process 'ForkPoolWorker-2' pid:3012960 exited with 'signal 9 (SIGKILL)'
[2026-10-23 10:59:52,197: ERROR/MainProcess] Task handler raised error: WorkerLostError('Worker exited prematurely: signal 9 (SIGKILL) Job: 1.')
- exitcode N: something in the child called
exit()/os._exit(), often a C extension or a library that exits on a fatal error. - signal 9 (SIGKILL): the process was killed from outside. On Linux the usual culprit is the OOM killer (check
dmesgor the container's memory limit), or Celery's own hardtime_limit.
2. SIGKILL from a hard time limit is reported as TimeLimitExceeded
$ grep -E "ERROR|WARNING|succeeded" worker.log | cut -c1-200
[2026-10-23 11:00:02,602: ERROR/MainProcess] Task handler raised error: TimeLimitExceeded(2)
[2026-10-23 11:00:02,602: ERROR/MainProcess] Hard time limit (2s) exceeded for tasks.slow[9516fbc7-4263-400d-82aa-873f4c047dee]
[2026-10-23 11:00:02,709: ERROR/MainProcess] Process 'ForkPoolWorker-1' pid:3012968 exited with 'signal 9 (SIGKILL)'
[2026-10-23 11:00:03,783: WARNING/MainProcess] Soft time limit (1s) exceeded for tasks.slow_soft[e188cdea-0f12-4ba6-a058-dae7eb169b79]
[2026-10-23 11:00:03,792: INFO/ForkPoolWorker-2] Task tasks.slow_soft[e188cdea-0f12-4ba6-a058-dae7eb169b79] succeeded in 1.0103442892432213s: 'cleaned up'
When Celery itself kills the child for exceeding time_limit, the log also shows exited with 'signal 9 (SIGKILL)', but the task result is TimeLimitExceeded, not WorkerLostError. A WorkerLostError with SIGKILL and no "Hard time limit" line above it points to something outside Celery, usually memory. See Celery task timeout / time limits.
What to do
- Memory: lower
--concurrency, give the container more memory, or recycle children with--max-memory-per-child(KiB) /--max-tasks-per-child. - Retries: the task's own
autoretry_forcannot catch it. Celery documentsacks_late=Truewithtask_reject_on_worker_lost=Trueto requeue the message instead; only do that for idempotent tasks, because a task that always crashes will be redelivered in a loop.
Related: Celery chord error handling, Celery MaxRetriesExceededError, Celery link_error errback.
Frequently asked questions
What causes Celery WorkerLostError signal 9?
The prefork child was SIGKILLed from outside Celery, most often by the Linux OOM killer or a container memory limit.
Can I catch WorkerLostError inside a Celery task?
No. The process running the task is gone; the error is recorded by the parent worker process.
Is a Celery hard time limit reported as WorkerLostError?
No. Celery logs the SIGKILL but the result is TimeLimitExceeded.
Written with AI assistance. Measured on 2026-10-23 with Celery 5.6.3 (kombu 5.6.2, redis-py 8.1.0) on Python 3.13.5, Redis 7 (Docker) as broker and backend. Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; Celery and Redis are free.