Poison message

On this page 7

A poison message is a message in a queue or event stream that cannot be processed successfully no matter how often it is retried, typically because of malformed content, an unexpected schema or a business rule it violates. In reliability engineering for automation, the term describes the risk that one such message is redelivered endlessly, blocking a queue, consuming worker capacity or crashing consumers in a loop.

Handling poison messages is a core part of building reliable automated workflows. The usual remedy is to count delivery attempts, stop retrying after a limit and move the message to a dead letter queue where it can be inspected without disrupting normal traffic.

How a poison message disrupts processing

A poison message disrupts processing because most messaging systems use at-least-once delivery: when a consumer fails or does not acknowledge a message, the broker makes it available again. If the failure is caused by the message itself, every new attempt fails in the same way, creating a redelivery loop.

The damage depends on how the queue delivers messages. In a strictly ordered queue or a partition of an event log, the poison message sits at the head and blocks every message behind it. In a competing-consumers queue, other messages continue, but the poison message keeps consuming retries, log space and CPU, and it may repeatedly crash a worker process.

Typical causes are listed in the following table, together with the symptom they usually produce.

CauseExampleTypical symptom
Malformed payloadTruncated or invalid JSONParser exception on every attempt
Schema mismatchProducer added a required field the consumer rejectsValidation error after a deployment
Invalid business dataOrder references a deleted customerConstraint violation in the target system
Oversized messageAttachment exceeds consumer memory or API limitsOut-of-memory crash or rejected call
Unsupported version or encodingOld event version, wrong character setDeserialization failure
Consumer bugEdge case such as a null value or a leap daySame exception for one specific record
Common causes of poison messages

Detecting poison messages

Poison messages are detected by tracking how many times each message has been delivered and comparing that count with a threshold. Most brokers provide a delivery counter, and the consumer or the broker moves the message aside when the counter exceeds the configured maximum.

The mechanisms differ by platform, as the table below shows.

PlatformDetection mechanismTypical setting
Amazon SQSReceive count with a redrive policymaxReceiveCount, often 3 to 10
Azure Service BusDelivery count per messageMaxDeliveryCount, default 10
RabbitMQDelivery limit on quorum queues and dead-letter exchangedelivery-limit set per queue
Apache KafkaNo broker counter; handled in consumer codeRetry topics and a dead letter topic
IBM MQBackout count with a backout queueBackout threshold on the queue
Poison message handling in common messaging platforms

Detection must distinguish permanent failures from transient ones. A timeout from a busy database is transient and deserves retries with exponential backoff and jitter; a schema violation is permanent and should be routed aside after the first or second attempt instead of wasting the full retry budget.

Poison message, dead letter queue and retry policy

A poison message is the problem, while the dead letter queue and retry policy are parts of the remedy. The terms are often used together and sometimes confused, so the following comparison clarifies their roles.

ConceptWhat it isRole with poison messages
Poison messageA message that always fails processingThe fault that must be isolated
Retry policyRules for how often and when to retryLimits attempts before giving up
Exponential backoffIncreasing wait time between retriesPrevents tight failure loops
Dead letter queueSeparate queue for undeliverable messagesHolds the poison message for inspection
IdempotencySafe repetition of the same operationPrevents duplicate effects during retries
Error workflowAutomated handling path for failuresAlerts staff and starts remediation
Related reliability concepts

A message in a dead letter queue is not automatically a poison message. It may have expired, exceeded a size limit or been rejected by routing rules. Classifying dead-lettered messages by reason helps teams decide whether to fix data, fix code or simply replay.

Designing workflows that tolerate poison messages

Resilient workflows treat poison messages as expected events, not emergencies. The design goal is that one bad message never stops healthy traffic and never disappears without a trace.

  • Validate early at the consumer boundary and reject clearly invalid messages without retries.
  • Set a finite retry limit with backoff, typically three to five attempts for permanent-looking errors.
  • Preserve the original message and its metadata, including headers, error text and attempt count.
  • Alert on dead letter growth rather than on each individual failure.
  • Provide a replay path so fixed messages can be resubmitted once the cause is corrected.
  • Use non-blocking retry topics in ordered streams so one partition is not frozen.

The following table maps typical responses to the root cause once a poison message has been isolated.

Root causeRecommended actionReplay
Consumer bugFix and deploy the consumerReplay after deployment
Bad source dataCorrect data in the source systemReplay or discard if resent
Schema changeAdd backward-compatible handlingReplay all affected messages
Truly invalid requestNotify the sender or business ownerDiscard with a recorded reason
Resolving isolated poison messages

Common mistakes

The most damaging mistake is unlimited retries, which turns a single malformed record into a permanent load on the system. Other frequent errors include catching exceptions and silently acknowledging the message, which loses data without any record, and retrying immediately without delay, which floods logs and can trigger rate limits on downstream APIs.

Ordering requirements deserve special care. When strict order matters, for example for account balance updates, skipping a poison message may create inconsistent state, so the workflow may need to pause that entity’s stream while allowing other entities to continue.

A plain-language summary

A poison message is a task that can never be completed, for example a form with missing or garbled information. An automated system keeps trying to process it, fails and tries again, over and over.

The sensible solution is the same one an office would use. After a few failed tries, the problem item is put in a separate tray for a person to check. The rest of the work then continues normally.

An example from practice

An online retailer sends order events to a queue that feeds its warehouse system. After a checkout update, one order arrives with a quantity field written as text instead of a number, and the warehouse consumer throws an exception on every attempt.

Because the queue is configured with a maximum of five deliveries, the broker moves the order to a dead letter queue after the fifth failure. An alert notifies the integration team, which fixes the producer, corrects the record and replays it.

Thousands of other orders continue shipping during the incident, and the faulty order is fulfilled within an hour instead of blocking the warehouse feed for the entire day.