# Dead Letter Queue (/sdks/rust/how-to/queues/dead-letter-queue)



<Callout type="info" title="Which to use">
  This page is the task-oriented walkthrough: send a message with DLQ routing configured so it reroutes once retries are exhausted. For the `max_receive_count()`/`max_receive_queue()` builder-field reference — defaults and edge cases — see [Dead Letter Policy](./dead-letter-policy).
</Callout>

## Overview [#overview]

A &#x2A;*dead-letter queue (DLQ)** gives a poison message somewhere to go instead of looping through consumers forever. When a message keeps failing — a malformed payload, a downstream outage, a handler bug — retrying it forever wastes consumer cycles and blocks everything behind it. A DLQ takes that decision out of your hands: past a set number of failed attempts, the broker diverts the message to a separate channel instead of retrying it again.

Routing runs on two builder methods on `QueueMessageBuilder`: `max_receive_count()` and `max_receive_queue()`. Every failed delivery — a nack, a reject, or an expired visibility window — increments the receive count; past the threshold, the broker reroutes the message to the DLQ instead of redelivering it. The DLQ itself is an ordinary queue, consumed like any other channel.

**Gotchas:** the DLQ doesn't drain itself — a dedicated consumer must watch it. The count increments on *any* failed delivery, not just deliberate rejections — a slow consumer that lets the visibility window lapse counts the same as an explicit nack. A typo in the DLQ channel name quietly creates an unrelated channel instead of failing loudly.

## Prerequisites [#prerequisites]

* KubeMQ server running on `localhost:50000`
* Rust SDK installed (`cargo add kubemq`)

## Code [#code]

```rust title="main.rs"
use kubemq::prelude::*;
use kubemq::QueueMessageBuilder;

#[tokio::main]
async fn main() -> kubemq::Result<()> {
    let client = KubemqClient::builder()
        .host("localhost")
        .port(50000)
        .build()
        .await?;

    let channel = "rust-queues.dead-letter-queue";

    let msg = QueueMessageBuilder::new()
        .channel(channel)
        .body(b"may-fail-processing".to_vec())
        .max_receive_count(3)
        .max_receive_queue("rust-queues.dead-letter-queue.dlq")
        .build();

    let result = client.send_queue_message(msg).await?;
    println!("Sent with DLQ policy: id={}", result.message_id);

    client.close().await?;
    Ok(())
}
```

## How It Works [#how-it-works]

* `max_receive_count(3)` limits delivery attempts to 3 before routing to the dead-letter queue.
* `max_receive_queue` specifies the target channel for failed messages.
* The server automatically routes messages after the receive count is exceeded.
* Review timeouts, channel names, and client IDs before running against shared environments.
* Run the program while the server from the prerequisites is available.

## Related [#related]

* [Dead Letter Policy](/sdks/rust/how-to/queues/dead-letter-policy) — field-level reference for `max_receive_count`/`max_receive_queue`
* [Queues overview](/learn/queues)
* [Rust SDK Reference](/sdks/rust/reference/queues)
