Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
FREEDOM251

Freedom251 › Blog › dead-letter queues

Why Spring Boot RabbitMQ Messages Hit the DLQ—and How to Replay Them Safely

By Freedom251 Team · · 7 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A RabbitMQ message reaches a dead-letter queue (DLQ) only when a broker-side dead-letter route is configured and a dead-letter event occurs. In Spring AMQP, the common surprise is that a listener exception normally causes the message to be requeued—not dead-lettered—because defaultRequeueRejected defaults to true. Diagnose the broker’s recorded death reason, fix the cause, then replay with a finite retry limit and duplicate protection.

What puts a RabbitMQ message in a DLQ?

RabbitMQ dead-letters a message in four situations: a consumer rejects or negatively acknowledges it without requeue; its message TTL expires; a queue length limit causes it to be dropped; or a quorum queue exceeds its delivery limit. These events do not automatically mean a message will arrive in a DLQ: the source queue must have a dead-letter exchange (DLX), and that exchange must route the message to a destination queue. Without a configured DLX, a dead-lettered message can be discarded. RabbitMQ’s dead-letter exchange documentation describes the triggers and routing behavior.

As an Amazon Associate I earn from qualifying purchases.

Broker death reason What to investigate
rejected Whether the consumer rejected the delivery without requeue, including Spring container and recoverer behavior.
expired Message TTL or queue-level message TTL, plus where the message was positioned in the queue.
maxlen Queue length limits by message count or total message bytes, and the configured overflow behavior.
delivery_limit Whether the source is a quorum queue and what delivery limit applies.

Inspect the message’s x-death history and first/last death metadata. The reason, queue, and exchange recorded there help distinguish an application rejection from expiry, overflow, or a delivery-limit event. RabbitMQ uses the configured dead-letter routing key when one is set; otherwise it reuses the message’s original routing key or keys. Verify the DLX, its bindings, and the target queue rather than assuming the queue name alone determines the route. RabbitMQ documents these routing rules and death headers.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why does Spring Boot requeue a message instead?

With Spring AMQP’s default listener-container behavior, an exception does not by itself send a delivery to the DLQ. The container’s defaultRequeueRejected setting defaults to true, so a failed delivery is normally rejected and requeued. That can make the same message return repeatedly to a consumer without ever reaching the broker’s DLX. Spring documents the default and the container configuration in its listener-container reference.

When a delivery should be rejected rather than requeued, Spring supports setting defaultRequeueRejected to false or throwing AmqpRejectAndDontRequeueException. RabbitMQ can then dead-letter it if the source queue has a working DLX route; without that route, the non-requeued message is discarded. Spring’s exception-handling reference explains rejection behavior.

Some errors happen before the listener method runs, including message-conversion failures. Spring’s ConditionalRejectingErrorHandler treats defined irrecoverable failures as fatal and rejects them without requeue. It also has a safeguard for fatal messages already carrying x-death, intended to prevent a fatal message from circulating indefinitely through a TTL-based retry and DLQ pattern. See Spring’s exception-handler documentation for the fatal-error behavior.

Do not confuse publisher retries with listener retries

Spring Boot’s template retry configuration concerns failed publishing operations, such as a broker connection failure; the Boot reference says those retries are disabled by default. It is separate from listener-side retries and recovery after a business exception. Configuring publishing retries therefore does not, by itself, change whether a failed listener delivery is requeued or dead-lettered. Spring Boot’s AMQP reference describes its AMQP configuration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Check what the recoverer does

A recoverer determines the final disposition after retry handling. RejectAndDontRequeueRecoverer causes a non-requeued rejection, allowing the broker’s DLX configuration to handle the message. RepublishMessageRecoverer instead publishes the failure to an error exchange and adds diagnostic headers, including exception information and the original exchange and routing key. If that recoverer handles the final failure and acknowledges the original delivery, the broker will not subsequently send that delivery to its own DLX. For application-level republishing with confirmation handling, Spring provides RepublishMessageRecovererWithConfirms. Spring’s resilience reference covers these recovery options.

How to identify the actual cause

  1. Read the message and its properties. Record the body, headers, original exchange, routing key, and any exception details added by Spring.
  2. Check the broker death history. Look at x-death and first/last death metadata for the reason, queue, and exchange. Use this to distinguish rejection, expiry, queue overflow, and quorum delivery-limit events.
  3. Inspect the source queue’s configuration. Confirm its DLX and any dead-letter routing key, then verify the exchange binding and destination queue. For overflow, inspect both queue limits and overflow behavior; for expiry, distinguish per-message or queue-level message TTL from expiration of the queue itself.
  4. Check listener disposition and recovery. Determine whether the container requeues, a recoverer republishes, or a conversion/error handler rejects without requeue. A listener exception alone does not establish which outcome occurred.

TTL and queue expiry are different

A message can expire under a per-message TTL or a queue-level message TTL. RabbitMQ does not deliver expired messages, but when expiry is noticed and the message is dead-lettered can depend on its position: quorum queues dead-letter expired messages when they reach the head. Expiration of the queue itself is different—RabbitMQ says messages in a queue that expires are not dead-lettered. RabbitMQ’s TTL documentation explains message and queue expiration.

Queue limits can affect publishers too

Limits may constrain the number of messages or their total size. Depending on the configured overflow behavior, RabbitMQ can drop older messages or reject new publications. Check publisher confirms as well as the DLQ: a rejected publication is not the same event as a message later dead-lettered from a queue. RabbitMQ’s DLX reference describes queue length limits and overflow behavior.

How to replay dead-lettered messages safely

  1. Diagnose before replay. Capture the death reason and routing details, plus any Spring exception headers. Identify whether the failure was rejection, expiry, overflow, or delivery-limit exhaustion.
  2. Fix the failure first. Correct the relevant code, data, schema, downstream dependency, or queue policy. Replaying unchanged poison messages to the same failing consumer is likely to produce the same failure.
  3. Select the destination deliberately. A replay consumer can publish to the original exchange and routing key, or route to the source queue if that matches the intended topology. Confirm the exchange exists and that its bindings route to the right queue before sending.
  4. Set a finite retry ceiling. Track attempts, apply backoff or delay where appropriate, and send messages that exceed the limit to a terminal parking-lot queue for investigation. Spring Cloud Stream’s Rabbit binder documentation shows a DLQ listener routing back to the original destination with a parking-lot queue after bounded attempts; it also describes using RabbitTemplate.receive() in a batch process. See the binder’s DLQ processing example.
  5. Make the business operation idempotent. A publish can succeed even if the replay process loses its acknowledgement, and a broker may retry forwarding. Deduplicate using a stable message or business identifier so processing a duplicate does not repeat an irreversible operation.
  6. Confirm publication and acknowledge deliberately. Handle publisher confirms and returned messages where supported, and acknowledge the DLQ delivery only after the republish has succeeded according to your design. Spring’s confirmed republisher can detect negative acknowledgments and returned messages. Spring documents confirmed recoverer behavior.

A DLQ-to-main-queue TTL loop without an attempt limit is not a bounded retry policy. Spring’s fatal-message safeguard specifically addresses a risk of fatal messages cycling through TTL-based retry and DLQ routing; use a retry ceiling and a terminal route instead. Spring’s exception-handling reference describes the safeguard.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Choose a recovery design that matches the failure

Approach Useful when Key control
In-process listener retry A failure may clear quickly without moving the message to another queue. Finite attempts and suitable backoff; define what happens when retries are exhausted.
Broker-delayed retry Messages need a delay before another attempt. Bound the retry cycle and guard against fatal messages circulating indefinitely.
Operator-controlled DLQ replay Messages need diagnosis or a fix before processing resumes. Choose the target route, confirm publication, and retain a terminal parking-lot path.
Application republish recovery Failure details should be sent to an application-managed error exchange. Account for the recoverer’s acknowledgment behavior and publication confirmation.

There is no single recovery policy suitable for every application. Classify errors as transient or permanent, decide whether retry is in-process, broker-delayed, or operator-controlled, and specify the attempt limit, duplicate strategy, and final destination before enabling replay.

Version-specific checks for quorum queues and retry counts

RabbitMQ 4.0 introduced a default quorum-queue delivery limit of 20; older RabbitMQ 3.x behavior was unlimited. If x-death reports delivery_limit, check the broker version and any policy override before diagnosing why the limit was reached. RabbitMQ’s quorum-queue documentation covers the limit and related settings.

Quorum-queue at-least-once dead-lettering is opt-in. RabbitMQ requires dead-letter-strategy=at-least-once, overflow=reject-publish, and a configured DLX. The default at-most-once handoff can lose a message if the target is unavailable or routing is wrong; at-least-once forwarding can retry but may produce duplicates. Design the consumer and replay process to tolerate those duplicates. See RabbitMQ’s quorum queue configuration and delivery guarantees.

Spring AMQP 3.2 introduced the retry_count header for tracking manually republished retries in conjunction with RabbitMQ 4.0’s changed handling of client-supplied x-* headers. When server-side dead-lettering is active and no retry count is present, Spring maps the broker’s x-death.count; an application performing manual republishing should increment retry_count. Check the deployed Spring AMQP version and the MessageProperties API before relying on that header.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

dead-letter queuesmessage replayRabbitMQSpring AMQPSpring Boot

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
Outdated Drivers Are Slowing You DownFree scan - exact matches
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.