Celery task stuck in PENDING: queue routing (tested)
If a Celery task stays PENDING forever, check the worker's [queues] banner. A task routed to images by task_routes is never picked up by a worker that only consumes celery. Start the worker with -Q celery,images.
A Celery worker consumes only the queues listed under [queues] in its startup banner; by default that is just celery. If task_routes (or apply_async(queue=...)) sends a task to another queue, the message waits in the broker and the task stays PENDING with no error anywhere. Measured with Celery 5.6.3 and Redis 7.
1. Routed to a queue nobody consumes
$ cat celery_app.py
from celery import Celery
app = Celery("proj", broker="redis://127.0.0.1:8964/0", backend="redis://127.0.0.1:8964/1")
app.conf.task_routes = {"celery_app.resize": {"queue": "images"}}
@app.task
def resize(n):
return f"resized {n}"
$ celery -A celery_app worker -c 1 --loglevel=INFO > worker.log 2>&1 &
$ timeout 30 python send.py
caller: TimeoutError The operation timed out. | state: PENDING
$ grep -A1 "\[queues\]" worker.log | sed -E "s/ +exchange=.*//"
-------------- [queues]
.> celery
$ python -c "import redis; print('images queue length:', redis.Redis(port=8964).llen('images'))"
images queue length: 1
The worker listens on celery only. The task went to images, so get() timed out, the state is PENDING (Celery also reports PENDING for unknown task ids), and the message is still sitting in the Redis list images.
2. Fix: tell the worker which queues to consume
$ celery -A celery_app worker -c 1 -Q celery,images --loglevel=INFO > worker.log 2>&1 &
$ timeout 30 python send.py
result: resized 1
$ grep -A2 "\[queues\]" worker.log | sed -E "s/ +exchange=.*//"
-------------- [queues]
.> celery
.> images
With -Q celery,images the banner lists both queues and the task runs. You can also run a dedicated worker per queue (-Q images). The message already waiting from step 1 was not lost: Redis kept it until a consumer appeared.
Other reasons a task stays PENDING: no worker running at all, the worker and client use different broker URLs or Redis database numbers, or no result backend is configured. Related: Celery Received unregistered task, celery beat vs worker, Celery Error 111.
Frequently asked questions
Why is my Celery task always PENDING?
No worker consumes the queue the task was sent to (check task_routes and the worker's -Q), no worker is running, or client and worker use different brokers.
How do I make a Celery worker consume a specific queue?
Start it with -Q, e.g. celery -A proj worker -Q celery,images. The banner's [queues] section lists what it consumes.
Is the message lost if no worker consumes the queue?
No. With Redis the message stayed in the queue's list until a worker consuming that queue started.
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.