[← Acknowledgement](05-acknowledgement.md) · [Module README](../README.md) # 6. Changing your mind about a queue Queue arguments are immutable. There is no `ALTER QUEUE`. Redeclaring an existing queue with different arguments is a channel-level error ([`docs/output/precondition-failed.txt`](output/precondition-failed.txt)): ``` PRECONDITION_FAILED - inequivalent arg 'x-message-ttl' for queue 'orders.ttl' in vhost '/': received '9999' but current is '1500', class-id=50, method-id=10 ``` Reply code **406**. The message is precise and helpful, and you will probably never see it, because of what Spring wraps it in: ``` AmqpIOException: java.io.IOException caused by: null caused by: channel error; protocol method: #method(reply-code=406, ...) ``` `AmqpIOException`'s own message is the string `java.io.IOException`. The next cause's message is `null`. The useful text is two levels down. This is why the failure gets reported as "some IOException from RabbitMQ" and why it is worth writing a log statement that walks the cause chain. ## What this means operationally Changing a TTL, a max-length, a dead-letter exchange or a queue type on a live queue is not a config edit. It is a migration: 1. declare the new queue under a new name 2. bind it alongside the old one 3. move consumers over 4. drain the old queue 5. delete it Plan the rename into the change from the start — `orders.work.v2` is not ugly, it is honest. ## Related failure modes **A failed declaration stops the ones after it.** `RabbitAdmin` declares beans on connection, and a `PRECONDITION_FAILED` closes the channel. Declarations queued behind it on that channel do not happen. So one stale queue argument can leave half your topology undeclared, and the symptom is a *different* queue being missing. **Declarations happen on connection, not on context refresh.** A broken topology does not fail startup; it fails the first publish. If you want it to fail at boot, force a connection early — `connectionFactory.createConnection()` in an `ApplicationRunner` is enough. **`missing-queues-fatal` defaults differently for the two container types.** It is `true` for `spring.rabbitmq.listener.simple` and `false` for `spring.rabbitmq.listener.direct`. So the same missing queue kills a simple container and is quietly tolerated by a direct one, which makes "it works in that service" an unhelpful data point. Combined with the point above, a topology error can present as a listener startup problem in one service and as silence in another. [Module README](../README.md)