RabbitMQ Error Guide: 'PRECONDITION_FAILED' Inequivalent Arg for Queue
Fix RabbitMQ PRECONDITION_FAILED inequivalent arg errors: reconcile durable, auto-delete, x-message-ttl, x-queue-type, and DLX mismatches on redeclared queues.
- #rabbitmq
- #troubleshooting
- #errors
- #queues
Overview
A PRECONDITION_FAILED - inequivalent arg error happens when a client declares a queue (or exchange) that already exists, but with different properties than the live one. RabbitMQ treats queue.declare as an assertion: if the existing queue’s durable, auto-delete, exclusive, or x-arguments do not match exactly what you pass, the broker refuses and closes the channel rather than silently mutating the queue.
You will see it in the client as a channel-level error (code 406):
Channel error on connection <0.1287.0> (10.0.5.31:51544 -> 10.0.4.21:5672, vhost: '/', user: 'app'):
operation queue.declare caused a channel exception precondition_failed:
inequivalent arg 'durable' for queue 'orders' in vhost '/':
received 'true' but current is 'false'
Or for an argument mismatch:
PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue 'jobs' in vhost '/':
received the value '60000' of type 'signedint' but current is none
This is a configuration drift problem: two pieces of code (or two deploys) disagree on how the queue should be defined. The queue itself is fine — the redeclaration is what is rejected.
Symptoms
- Channel closes immediately on startup with
PRECONDITION_FAILED - inequivalent arg. - The error names the exact argument (
durable,x-message-ttl,x-queue-type, etc.) and shows received vs. current. - Only some clients fail — the ones whose declaration disagrees with whoever created the queue first.
rabbitmqctl list_queues name durable auto_delete arguments | grep orders
orders false false []
The live orders queue is durable=false with no arguments; a client asserting durable=true triggers the error.
Common Root Causes
1. Durable flag mismatch
The most common case: one client declares the queue durable, another non-durable.
rabbitmqctl list_queues name durable | grep payments
payments false
A producer started with durable=true will be refused because the existing payments is transient. Either the queue must be recreated durable, or the producer must match.
2. x-message-ttl differs or is set on only one side
A per-queue TTL declared by one client but not the other (or with a different value) is an inequivalent arg.
rabbitmqctl list_queues name arguments | grep jobs
jobs [{"x-message-ttl",60000}]
A client declaring jobs with no x-message-ttl, or x-message-ttl=120000, is refused. The argument and its value must match exactly.
3. x-queue-type mismatch (classic vs. quorum)
Migrating to quorum queues is a frequent trigger: the queue exists as classic but a new deploy asserts quorum (or vice versa).
rabbitmqctl list_queues name type | grep audit
audit classic
A client passing x-queue-type=quorum for audit gets inequivalent arg 'x-queue-type'. Queue type cannot be changed in place — the queue must be deleted and recreated.
4. Dead-letter exchange / routing key mismatch
x-dead-letter-exchange or x-dead-letter-routing-key declared differently across clients.
rabbitmqctl list_queues name arguments | grep tasks
tasks [{"x-dead-letter-exchange","dlx"},{"x-dead-letter-routing-key","tasks.dead"}]
A client declaring tasks with a different DLX, or none, is refused. All declarers must agree on the DLX arguments.
5. auto-delete or exclusive flag mismatch
A queue first declared auto-delete or exclusive cannot be redeclared with those flags flipped.
rabbitmqctl list_queues name auto_delete exclusive | grep notify
notify true false
A client asserting auto_delete=false on the existing auto-delete notify queue gets an inequivalent arg on auto-delete.
6. x-max-length / x-max-length-bytes / overflow drift
Length-limit arguments declared inconsistently across producers and consumers.
rabbitmqctl list_queues name arguments | grep stream-buffer
stream-buffer [{"x-max-length",100000},{"x-overflow","reject-publish"}]
A client declaring the same queue without x-max-length, or with drop-head overflow, is refused. Align the limit arguments on every declarer.
Diagnostic Workflow
Step 1: Read the exact argument and the received vs. current values
The error message itself names the offending arg, e.g. inequivalent arg 'x-message-ttl' ... received '60000' but current is none. This tells you precisely what to reconcile — no guessing.
Step 2: Inspect the live queue’s real definition
rabbitmqctl list_queues name durable auto_delete exclusive type arguments | grep <QUEUE>
Compare each field to what the failing client declares. The arguments column shows TTL, DLX, queue-type, and length limits as the broker actually holds them.
Step 3: Find who declared it first / differently
# via management API: which client and properties created it
rabbitmqadmin list queues name node messages arguments
Trace the declaration to the deploy or service that created the queue with the current properties. The “first writer wins” — everyone else must match it or the queue must be rebuilt.
Step 4: Decide reconcile vs. recreate
Durability, queue-type, and most x-arguments cannot be changed on a live queue. If the desired definition differs from current, you must delete and recreate (after draining), or change the client to match the existing definition.
rabbitmqctl list_queues name messages | grep <QUEUE>
Check the message count before deleting so you do not lose data.
Step 5: Recreate with the agreed definition (if needed)
# Drain or migrate messages first, then:
rabbitmqctl delete_queue <QUEUE>
# Let the corrected client redeclare it, or declare explicitly:
rabbitmqadmin declare queue name=<QUEUE> durable=true \
arguments='{"x-queue-type":"quorum","x-message-ttl":60000}'
After recreation, every client must use this identical definition.
Example Root Cause Analysis
A consumer deploy starts failing on boot with:
PRECONDITION_FAILED - inequivalent arg 'x-queue-type' for queue 'audit' in vhost '/':
received 'quorum' but current is 'classic'
The team had updated the consumer to request quorum queues for durability, but the audit queue was created months ago as a classic queue and still holds messages. Quorum vs. classic is a structural property that cannot be altered in place, so the redeclaration is refused.
Confirming the live state:
rabbitmqctl list_queues name type messages | grep audit
audit classic 4120
Fix: drain the 4120 messages (let the existing classic consumers finish, or shovel them to a temporary queue), then delete and recreate as quorum:
rabbitmqctl delete_queue audit
rabbitmqadmin declare queue name=audit durable=true \
arguments='{"x-queue-type":"quorum"}'
Both producers and consumers are then redeployed with the quorum declaration so all sides agree. The error clears because the assertion now matches the live queue.
Prevention Best Practices
- Define queue topology in one place — a shared schema, an init job, or RabbitMQ definitions JSON — so no two services can declare the same queue differently.
- Use
rabbitmqctl import_definitions/ the definitions file to declare queues once at provisioning, and have apps declare withpassive=true(assert existence only, no arguments) where possible. - Treat queue-type and durability changes as recreate operations with an explicit drain/migrate step, never as an in-place edit.
- Pin x-arguments (TTL, DLX, length limits) in shared client config so a single deploy cannot drift one value.
- Add a CI check that diffs each service’s declared queue properties against the canonical definitions before release.
- When an inequivalent-arg page fires, the free incident assistant can map the received-vs-current values to the offending deploy. See related fixes in the RabbitMQ guides.
Quick Command Reference
# Live queue definition (compare to client declaration)
rabbitmqctl list_queues name durable auto_delete exclusive type arguments | grep <QUEUE>
# Message count before any recreate
rabbitmqctl list_queues name messages | grep <QUEUE>
# Inspect via management API
rabbitmqadmin list queues name node messages arguments
# Recreate with the agreed definition
rabbitmqctl delete_queue <QUEUE>
rabbitmqadmin declare queue name=<QUEUE> durable=true \
arguments='{"x-queue-type":"quorum","x-message-ttl":60000}'
# Bulk-declare from canonical definitions
rabbitmqctl import_definitions /etc/rabbitmq/definitions.json
Conclusion
PRECONDITION_FAILED - inequivalent arg means a redeclaration disagrees with the live queue. The broker protects the existing queue by refusing rather than mutating it. The usual root causes:
- A
durable(orauto-delete/exclusive) flag mismatch between declarers. - An
x-message-ttlset or valued differently across clients. - An
x-queue-typechange (classic vs. quorum) that cannot be applied in place. - Dead-letter exchange/routing-key arguments that differ.
- Length-limit arguments (
x-max-length, overflow) declared inconsistently.
Read the received-vs-current values in the error, inspect the live queue, then either align the client to the existing definition or drain-and-recreate when the property is immutable.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.