Jump to solution
Verify

The Fix

pip install celery==5.5.0

Based on closed celery/celery issue #6067 · PR/commit linked

Production note: This usually shows up under retries/timeouts. Treat it as a side-effect risk until you can verify behavior with a canary + real traffic.

Jump to Verify Open PR/Commit
@@ -249,9 +249,13 @@ def Queues(self, queues, create_missing=None, max_priority = conf.task_queue_max_priority if not queues and conf.task_default_queue: + queue_arguments = None + if conf.task_default_queue_type == 'quorum': + queue_arguments = {'x-queue-type': 'quorum'}
repro.py
from celery import bootsteps class NoChannelGlobalQoS(bootsteps.StartStopStep): requires = {'celery.worker.consumer.tasks:Tasks'} def start(self, c): qos_global = False c.connection.default_channel.basic_qos( 0, c.initial_prefetch_count, qos_global, ) def set_prefetch_count(prefetch_count): return c.task_consumer.qos( prefetch_count=prefetch_count, apply_global=qos_global, ) c.qos = QoS(set_prefetch_count, c.initial_prefetch_count) app.steps['consumer'].add(NoChannelGlobalQoS)
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Upgrade to fixed release\npip install celery==5.5.0\nWhen NOT to use: This fix should not be used if backward compatibility with older queue types is required.\n\nOption C — Workaround\nbut I think the expected behaviour is that a celery user, after having setup rabbitmq using [commonly advised queue configurations](https://www.cloudamqp.com/blog/reasons-you-should-switch-to-quorum-queues.html) should be able to connect to the rabbit hosts and start submitting and consuming tasks. If i understand this will currently fail?\nWhen NOT to use: This fix should not be used if backward compatibility with older queue types is required.\n\n

Why This Fix Works in Production

  • Trigger: amqp.exceptions.AMQPNotImplementedError: Basic.consume: (540) NOT_IMPLEMENTED - queue 'celery' in vhost '/' does not support global qos
  • Mechanism: The library lacked support for configuring quorum queues in RabbitMQ
  • Why the fix works: Added support for quorum queues in Celery, allowing users to configure queues with the 'quorum' type for better reliability. (first fixed release: 5.5.0).
Production impact:
  • If left unfixed, retries/timeouts can trigger duplicate external side-effects (double charges, duplicate emails, repeated writes).

Why This Breaks in Prod

  • Triggered by an upgrade/regression window: 01.405553–52.477317 breaks; 5.5.0 is the first fixed release.
  • Shows up under Python 3.12.1 in real deployments (not just unit tests).
  • The library lacked support for configuring quorum queues in RabbitMQ
  • Surfaces as: amqp.exceptions.AMQPNotImplementedError: Basic.consume: (540) NOT_IMPLEMENTED - queue 'celery' in vhost '/' does not support global qos

Proof / Evidence

  • GitHub issue: #6067
  • Fix PR: https://github.com/celery/celery/pull/9121
  • First fixed release: 5.5.0
  • Affected versions: 01.405553–52.477317
  • Reproduced locally: No (not executed)
  • Last verified: 2026-02-09
  • Confidence: 0.85
  • Did this fix it?: Yes (upstream fix exists)
  • Own content ratio: 0.42

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“Is there any update on this? Since RabitMQ itself will deprecate classic queues. https://blog.rabbitmq.com/posts/2021/08/4.0-deprecation-announcements/”
@CN91 · 2022-09-20 · source
“Celery v5.5.0b1 was released, including a fix for this issue. Take note ETA tasks were not handled. See #9149 for possible further updates.”
@Nusnus · 2024-07-24 · confirmation · source
“Yes, it fails for me. Until celery is updated to support per-consumer QOS it won't work with quorum queues.”
@noelmcloughlin · 2021-08-02 · source
“> RabitMQ itself will deprecate classic queues”
@miraculixx · 2022-11-06 · source

Failure Signature (Search String)

  • amqp.exceptions.AMQPNotImplementedError: Basic.consume: (540) NOT_IMPLEMENTED - queue 'celery' in vhost '/' does not support global qos

Error Message

Stack trace
error.txt
Error Message ------------- amqp.exceptions.AMQPNotImplementedError: Basic.consume: (540) NOT_IMPLEMENTED - queue 'celery' in vhost '/' does not support global qos
Stack trace
error.txt
Error Message ------------- [2024-09-16 10:33:52,524: CRITICAL/MainProcess] Unrecoverable error: AttributeError("'list' object has no attribute 'startswith'") Traceback (most recent call last): File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/worker/worker.py", line 203, in start self.blueprint.start(self) File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/bootsteps.py", line 116, in start step.start(parent) File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/bootsteps.py", line 365, in start return self.obj.start() File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/worker/consumer/consumer.py", line 340, in start blueprint.start(self) File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/bootsteps.py", line 116, in start step.start(parent) File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/worker/consumer/tasks.py", line 44, in start qos_global = self.qos_global(c) File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/worker/consumer/tasks.py", line 93, in qos_global using_quorum_queues, qname = self.detect_quorum_queues(c) File "/var/opt/celery/celery_venv/lib/python3.10/site-packages/celery/worker/consumer/tasks.py", line 110, in detect_quorum_queues is_rabbitmq_broker = c.app.conf.broker_url.startswith(("amqp", "pyamqp")) Attrib ... (truncated) ...

Minimal Reproduction

repro.py
from celery import bootsteps class NoChannelGlobalQoS(bootsteps.StartStopStep): requires = {'celery.worker.consumer.tasks:Tasks'} def start(self, c): qos_global = False c.connection.default_channel.basic_qos( 0, c.initial_prefetch_count, qos_global, ) def set_prefetch_count(prefetch_count): return c.task_consumer.qos( prefetch_count=prefetch_count, apply_global=qos_global, ) c.qos = QoS(set_prefetch_count, c.initial_prefetch_count) app.steps['consumer'].add(NoChannelGlobalQoS)

Environment

  • Python: 3.12.1

What Broke

Users experienced failures when attempting to use quorum queues with Celery.

Why It Broke

The library lacked support for configuring quorum queues in RabbitMQ

Fix Options (Details)

Option A — Upgrade to fixed release Safe default (recommended)

pip install celery==5.5.0

When NOT to use: This fix should not be used if backward compatibility with older queue types is required.

Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.

Option C — Workaround Temporary workaround

but I think the expected behaviour is that a celery user, after having setup rabbitmq using [commonly advised queue configurations](https://www.cloudamqp.com/blog/reasons-you-should-switch-to-quorum-queues.html) should be able to connect to the rabbit hosts and start submitting and consuming tasks. If i understand this will currently fail?

When NOT to use: This fix should not be used if backward compatibility with older queue types is required.

Use only if you cannot change versions today. Treat this as a stopgap and remove once upgraded.

Option D — Guard side-effects with OnceOnly Guardrail for side-effects

Mitigate duplicate external side-effects under retries/timeouts/agent loops by gating the operation before calling external systems.

  • Place OnceOnly between your code/agent and real side-effects (Stripe, emails, CRM, APIs).
  • Use a stable key per side-effect (e.g., customer_id + action + idempotency_key).
  • Fail-safe: configure fail-open vs fail-closed based on blast radius and spend risk.
  • This is most useful when retries/timeouts can re-trigger the same external call.
Show example snippet (optional)
onceonly.py
from onceonly import OnceOnly import os once = OnceOnly(api_key=os.environ["ONCEONLY_API_KEY"], fail_open=True) # Stable idempotency key per real side-effect. # Use a request id / job id / webhook delivery id / Stripe event id, etc. event_id = "evt_..." # replace key = f"stripe:webhook:{event_id}" res = once.check_lock(key=key, ttl=3600) if res.duplicate: return {"status": "already_processed"} # Safe to execute the side-effect exactly once. handle_event(event_id)

See OnceOnly SDK

When NOT to use: Do not use this to hide logic bugs or data corruption. Use it to block duplicate external side-effects and enforce tool permissions/spend caps.

Fix reference: https://github.com/celery/celery/pull/9121

First fixed release: 5.5.0

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix should not be used if backward compatibility with older queue types is required.
  • Do not use this to hide logic bugs or data corruption. Use it to block duplicate external side-effects and enforce tool permissions/spend caps.

Verify Fix

verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.

Did This Fix Work in Your Case?

Quick signal helps us prioritize which fixes to verify and improve.

Prevention

  • Capture the exact failing error string in logs and tests so you can reproduce via a minimal script.
  • Pin production dependencies and upgrade only with a reproducible test that hits the failing path.

Version Compatibility Table

VersionStatus
01.405553 Broken
21.576442 Broken
24.611430 Broken
26.505187 Broken
33.588267 Broken
52.477317 Broken
5.5.0 Fixed

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.