The "Poison Pill" Problem
Imagine a message arrives in your queue with a malformed JSON body — a syntax error introduced by a bug in the producer. Your consumer application tries to parse it, throws an exception, and crashes without calling DeleteMessage. The Visibility Timeout expires, the message reappears, and the cycle repeats indefinitely.
This is called a poison pill message. It:
- Burns compute resources (Lambda invocations cost money).
- Blocks processing of legitimate messages behind it (in FIFO queues).
- Generates a flood of error logs and alarms.
- Can exhaust your consumer's retry budget, causing it to stop processing entirely.
The DLQ Solution
A Dead Letter Queue (DLQ) is a standard SQS queue that you designate as a holding area for messages that have repeatedly failed processing. You configure a Redrive Policy on your source queue:
"If a message has been received (and not deleted) N times — called the
maxReceiveCount— move it to the DLQ automatically."
A maxReceiveCount of 3–5 is typical. After 5 failed attempts, SQS moves the message to the DLQ and stops retrying. Your main queue is unblocked.
What to Do with DLQ Messages
The DLQ is not a trash can — it's a quarantine. Standard practice:
- Alarm on DLQ depth: Set a CloudWatch alarm that fires when
ApproximateNumberOfMessagesVisiblein the DLQ exceeds 0. Any message in the DLQ is a bug that needs investigation. - Inspect the message: Read the raw message body to understand why it failed.
- Fix the bug: Patch the producer (if the message is malformed) or the consumer (if it can't handle a valid edge case).
- Redrive: Use SQS's Dead-Letter Queue Redrive feature to replay DLQ messages back to the source queue after the fix is deployed.
DLQ for SNS
SNS also supports DLQs, but at the subscription level, not the topic level. If SNS cannot deliver a message to a subscribed SQS queue (e.g., the queue was deleted), it can send the undelivered message to a DLQ attached to that subscription. This catches delivery failures that happen between SNS and SQS, not just processing failures inside the consumer.
Interviewers sometimes ask: "How do you handle a poison pill message in SQS?" A weak answer is "use a DLQ." A strong answer explains the full lifecycle: configure maxReceiveCount on the redrive policy, alarm on DLQ depth with CloudWatch, inspect and fix the root cause, then use the SQS Redrive feature to replay messages. Also mention that for FIFO queues, a poison pill is especially dangerous because it blocks all messages in the same Message Group ID — making DLQ configuration even more critical there.