[{"data":1,"prerenderedAt":570},["ShallowReactive",2],{"content-query-i6r45Q496K":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"layout":10,"crumb":11,"term":11,"summary":12,"group":13,"order":14,"updated":15,"cta":16,"related":24,"faq":43,"body":56,"_type":563,"_id":564,"_source":565,"_file":566,"_stem":567,"_extension":568,"sitemap":569},"/glossary/dead-letter-queue","glossary",false,"","What is a dead-letter queue (DLQ)? Definition and examples","A dead-letter queue (DLQ) holds messages that couldn't be processed or delivered after all retries, so they aren't lost. How DLQs work in SQS and for webhooks, and how to handle them.","reference","Dead-letter queue","Where messages go after they run out of retries, so they aren't lost.","Delivery and reliability",24,"2026-10-28",{"eyebrow":17,"title":18,"text":19,"to":20,"label":21,"secondaryTo":22,"secondaryLabel":23},"Webhook Relay","See and recover every failed webhook","Webhook Relay logs every delivery attempt. Failed deliveries stay visible with their responses, and you can resend one, recover failed deliveries in bulk after an outage, or replay missed events, without asking the provider to send them again.","/features/webhook-logs/","See webhook logs","/features/durable-retries/","Durable retries",[25,28,31,34,37,40],{"title":26,"to":27},"Webhook retries","/glossary/webhook-retries/",{"title":29,"to":30},"Webhook replay","/glossary/webhook-replay/",{"title":32,"to":33},"At-least-once delivery","/glossary/at-least-once-delivery/",{"title":35,"to":36},"Exponential backoff","/glossary/exponential-backoff/",{"title":38,"to":39},"Idempotency","/glossary/idempotency/",{"title":41,"to":42},"Webhook to SQS","/blog/webhook-to-sqs/",[44,47,50,53],{"q":45,"a":46},"What is a dead-letter queue?","A dead-letter queue, or DLQ, is a separate queue where a messaging system puts messages it could not process or deliver after a set number of attempts. Moving them aside stops one bad message from blocking or endlessly retrying in the main queue, and keeps it available for inspection and reprocessing.",{"q":48,"a":49},"Why do messages end up in a dead-letter queue?","Usually because processing kept failing: the message is malformed, a bug crashes the consumer on that input, a downstream service has been down longer than the retry window, or the message is too large or expired. In webhook delivery, the most common reason is an endpoint that stayed down or kept returning errors after every retry.",{"q":51,"a":52},"What should I do with messages in a dead-letter queue?","Alert on them, find the cause, fix it, then redrive or replay the messages to the original destination. Make sure consumers are idempotent first, because some messages in a DLQ may have been partially processed.",{"q":54,"a":55},"Do webhooks have a dead-letter queue?","Some webhook senders and gateways keep failed deliveries in a failed state or a DLQ that you can inspect and replay. Many providers do not and simply drop the event after the last retry, which is why receivers often put a gateway or queue in front of their endpoint.",{"type":57,"children":58,"toc":556},"root",[59,73,172,185,192,237,242,248,292,298,318,335,345,398,404,409,485,491,550],{"type":60,"tag":61,"props":62,"children":63},"element","p",{},[64,71],{"type":60,"tag":65,"props":66,"children":67},"strong",{},[68],{"type":69,"value":70},"text","A dead-letter queue (DLQ) is a holding area for messages that couldn't be processed or delivered after a set number of attempts.",{"type":69,"value":72}," Instead of retrying a failing message forever, or silently dropping it, the system moves it aside to the DLQ. The main queue keeps flowing, and the failed message stays available for someone to inspect, fix and replay.",{"type":60,"tag":74,"props":75,"children":79},"pre",{"className":76,"code":77,"language":78,"meta":7,"style":7},"language-json shiki shiki-themes github-dark","{\n  \"RedrivePolicy\": {\n    \"deadLetterTargetArn\": \"arn:aws:sqs:eu-west-1:123456789012:orders-dlq\",\n    \"maxReceiveCount\": \"5\"\n  }\n}\n","json",[80],{"type":60,"tag":81,"props":82,"children":83},"code",{"__ignoreMap":7},[84,96,111,136,154,163],{"type":60,"tag":85,"props":86,"children":89},"span",{"class":87,"line":88},"line",1,[90],{"type":60,"tag":85,"props":91,"children":93},{"style":92},"--shiki-default:#E1E4E8",[94],{"type":69,"value":95},"{\n",{"type":60,"tag":85,"props":97,"children":99},{"class":87,"line":98},2,[100,106],{"type":60,"tag":85,"props":101,"children":103},{"style":102},"--shiki-default:#79B8FF",[104],{"type":69,"value":105},"  \"RedrivePolicy\"",{"type":60,"tag":85,"props":107,"children":108},{"style":92},[109],{"type":69,"value":110},": {\n",{"type":60,"tag":85,"props":112,"children":114},{"class":87,"line":113},3,[115,120,125,131],{"type":60,"tag":85,"props":116,"children":117},{"style":102},[118],{"type":69,"value":119},"    \"deadLetterTargetArn\"",{"type":60,"tag":85,"props":121,"children":122},{"style":92},[123],{"type":69,"value":124},": ",{"type":60,"tag":85,"props":126,"children":128},{"style":127},"--shiki-default:#9ECBFF",[129],{"type":69,"value":130},"\"arn:aws:sqs:eu-west-1:123456789012:orders-dlq\"",{"type":60,"tag":85,"props":132,"children":133},{"style":92},[134],{"type":69,"value":135},",\n",{"type":60,"tag":85,"props":137,"children":139},{"class":87,"line":138},4,[140,145,149],{"type":60,"tag":85,"props":141,"children":142},{"style":102},[143],{"type":69,"value":144},"    \"maxReceiveCount\"",{"type":60,"tag":85,"props":146,"children":147},{"style":92},[148],{"type":69,"value":124},{"type":60,"tag":85,"props":150,"children":151},{"style":127},[152],{"type":69,"value":153},"\"5\"\n",{"type":60,"tag":85,"props":155,"children":157},{"class":87,"line":156},5,[158],{"type":60,"tag":85,"props":159,"children":160},{"style":92},[161],{"type":69,"value":162},"  }\n",{"type":60,"tag":85,"props":164,"children":166},{"class":87,"line":165},6,[167],{"type":60,"tag":85,"props":168,"children":169},{"style":92},[170],{"type":69,"value":171},"}\n",{"type":60,"tag":61,"props":173,"children":174},{},[175,177,183],{"type":69,"value":176},"This Amazon SQS policy moves any message that's been received five times without being deleted into the ",{"type":60,"tag":81,"props":178,"children":180},{"className":179},[],[181],{"type":69,"value":182},"orders-dlq",{"type":69,"value":184}," queue.",{"type":60,"tag":186,"props":187,"children":189},"h2",{"id":188},"how-a-dead-letter-queue-works",[190],{"type":69,"value":191},"How a dead-letter queue works",{"type":60,"tag":193,"props":194,"children":195},"ol",{},[196,202,207,220,225],{"type":60,"tag":197,"props":198,"children":199},"li",{},[200],{"type":69,"value":201},"A consumer receives a message from the main queue and tries to process it.",{"type":60,"tag":197,"props":203,"children":204},{},[205],{"type":69,"value":206},"Processing fails: the consumer crashes, throws, or doesn't acknowledge in time.",{"type":60,"tag":197,"props":208,"children":209},{},[210,212,218],{"type":69,"value":211},"The message becomes visible again and is retried, often with ",{"type":60,"tag":213,"props":214,"children":215},"a",{"href":36},[216],{"type":69,"value":217},"exponential backoff",{"type":69,"value":219},".",{"type":60,"tag":197,"props":221,"children":222},{},[223],{"type":69,"value":224},"After the maximum attempts (or a time limit), the broker moves it to the DLQ.",{"type":60,"tag":197,"props":226,"children":227},{},[228,230,235],{"type":69,"value":229},"An alert fires. Someone inspects the message, fixes the cause, and ",{"type":60,"tag":65,"props":231,"children":232},{},[233],{"type":69,"value":234},"redrives",{"type":69,"value":236}," it back to the main queue or replays it to the destination.",{"type":60,"tag":61,"props":238,"children":239},{},[240],{"type":69,"value":241},"SQS, Google Pub/Sub, Azure Service Bus, RabbitMQ (via dead-letter exchanges) and most job frameworks support this pattern. With Kafka, it's usually implemented as a separate topic that a consumer writes failed records to.",{"type":60,"tag":186,"props":243,"children":245},{"id":244},"why-you-want-one",[246],{"type":69,"value":247},"Why you want one",{"type":60,"tag":249,"props":250,"children":251},"ul",{},[252,262,272,282],{"type":60,"tag":197,"props":253,"children":254},{},[255,260],{"type":60,"tag":65,"props":256,"children":257},{},[258],{"type":69,"value":259},"No poison messages blocking the queue.",{"type":69,"value":261}," One malformed message that always crashes the consumer can stall everything behind it, especially with ordered queues.",{"type":60,"tag":197,"props":263,"children":264},{},[265,270],{"type":60,"tag":65,"props":266,"children":267},{},[268],{"type":69,"value":269},"No silent loss.",{"type":69,"value":271}," Without a DLQ, a message that runs out of retries is just gone.",{"type":60,"tag":197,"props":273,"children":274},{},[275,280],{"type":60,"tag":65,"props":276,"children":277},{},[278],{"type":69,"value":279},"A clear signal.",{"type":69,"value":281}," DLQ depth is one of the most useful alerts you can have. A non-empty DLQ means something needs attention.",{"type":60,"tag":197,"props":283,"children":284},{},[285,290],{"type":60,"tag":65,"props":286,"children":287},{},[288],{"type":69,"value":289},"Recovery after outages.",{"type":69,"value":291}," When a downstream service is down longer than the retry window, its messages wait in the DLQ until it's back.",{"type":60,"tag":186,"props":293,"children":295},{"id":294},"dead-letter-queues-and-webhooks",[296],{"type":69,"value":297},"Dead-letter queues and webhooks",{"type":60,"tag":61,"props":299,"children":300},{},[301,303,309,311,316],{"type":69,"value":302},"For webhooks, the \"queue\" is the sender's delivery pipeline and the consumer is your ",{"type":60,"tag":213,"props":304,"children":306},{"href":305},"/glossary/webhook-endpoint/",[307],{"type":69,"value":308},"endpoint",{"type":69,"value":310},". When every ",{"type":60,"tag":213,"props":312,"children":313},{"href":27},[314],{"type":69,"value":315},"retry",{"type":69,"value":317}," fails, the delivery has the same problem a dead message has: it has to go somewhere or be lost.",{"type":60,"tag":61,"props":319,"children":320},{},[321,326,328,333],{"type":60,"tag":65,"props":322,"children":323},{},[324],{"type":69,"value":325},"As a webhook sender",{"type":69,"value":327},", keep failed deliveries in a failed state or DLQ with the last response, show them to the customer, and offer a way to ",{"type":60,"tag":213,"props":329,"children":330},{"href":30},[331],{"type":69,"value":332},"replay",{"type":69,"value":334}," them once the endpoint is fixed. Disable endpoints that fail for a long time instead of retrying them forever.",{"type":60,"tag":61,"props":336,"children":337},{},[338,343],{"type":60,"tag":65,"props":339,"children":340},{},[341],{"type":69,"value":342},"As a webhook receiver",{"type":69,"value":344},", you don't control the provider's DLQ, and many providers don't have one: after their last retry, the event is dropped. Two common patterns protect you:",{"type":60,"tag":249,"props":346,"children":347},{},[348,380],{"type":60,"tag":197,"props":349,"children":350},{},[351,356,358,364,366,372,374,379],{"type":60,"tag":65,"props":352,"children":353},{},[354],{"type":69,"value":355},"Accept, then queue.",{"type":69,"value":357}," Your endpoint writes each verified webhook to your own queue and returns ",{"type":60,"tag":81,"props":359,"children":361},{"className":360},[],[362],{"type":69,"value":363},"200",{"type":69,"value":365},". Processing failures land in ",{"type":60,"tag":367,"props":368,"children":369},"em",{},[370],{"type":69,"value":371},"your",{"type":69,"value":373}," DLQ, where you can replay them. See ",{"type":60,"tag":213,"props":375,"children":376},{"href":42},[377],{"type":69,"value":378},"webhook to SQS",{"type":69,"value":219},{"type":60,"tag":197,"props":381,"children":382},{},[383,388,390,396],{"type":60,"tag":65,"props":384,"children":385},{},[386],{"type":69,"value":387},"Put a gateway in front.",{"type":69,"value":389}," A ",{"type":60,"tag":213,"props":391,"children":393},{"href":392},"/glossary/webhook-gateway/",[394],{"type":69,"value":395},"webhook gateway",{"type":69,"value":397}," stores every request before delivery and retries on its own schedule, so an endpoint outage doesn't depend on the provider's retry policy.",{"type":60,"tag":186,"props":399,"children":401},{"id":400},"how-webhook-relay-handles-failed-deliveries",[402],{"type":69,"value":403},"How Webhook Relay handles failed deliveries",{"type":60,"tag":61,"props":405,"children":406},{},[407],{"type":69,"value":408},"Webhook Relay doesn't call it a DLQ, but failed deliveries are kept and recoverable, which serves the same purpose:",{"type":60,"tag":249,"props":410,"children":411},{},[412,444],{"type":60,"tag":197,"props":413,"children":414},{},[415,420,422,427,429,434,436,442],{"type":60,"tag":65,"props":416,"children":417},{},[418],{"type":69,"value":419},"Inbound webhooks.",{"type":69,"value":421}," Each webhook is stored in the bucket's ",{"type":60,"tag":213,"props":423,"children":424},{"href":20},[425],{"type":69,"value":426},"logs",{"type":69,"value":428}," with every delivery attempt. With ",{"type":60,"tag":213,"props":430,"children":431},{"href":22},[432],{"type":69,"value":433},"durable retries",{"type":69,"value":435},", failing deliveries are shown as ",{"type":60,"tag":81,"props":437,"children":439},{"className":438},[],[440],{"type":69,"value":441},"stalled",{"type":69,"value":443}," and retried with backoff for up to 30 days. From the log you can resend any delivery, recover failed deliveries in bulk after an endpoint recovers, or replay missing events.",{"type":60,"tag":197,"props":445,"children":446},{},[447,452,454,460,462,468,470,476,478,484],{"type":60,"tag":65,"props":448,"children":449},{},[450],{"type":69,"value":451},"Outbound webhooks.",{"type":69,"value":453}," In the ",{"type":60,"tag":213,"props":455,"children":457},{"href":456},"/outbound-webhooks/",[458],{"type":69,"value":459},"Outbound Gateway",{"type":69,"value":461},", a delivery that runs out of retries (up to 8 attempts within 48 hours) is marked ",{"type":60,"tag":81,"props":463,"children":465},{"className":464},[],[466],{"type":69,"value":467},"failed",{"type":69,"value":469}," and kept for 35 days. Once the customer's endpoint is fixed, a recover call re-sends that endpoint's failed deliveries with the original ",{"type":60,"tag":81,"props":471,"children":473},{"className":472},[],[474],{"type":69,"value":475},"webhook-id",{"type":69,"value":477},". See ",{"type":60,"tag":213,"props":479,"children":481},{"href":480},"/docs/outbound/operating/",[482],{"type":69,"value":483},"monitor, retry and recover deliveries",{"type":69,"value":219},{"type":60,"tag":186,"props":486,"children":488},{"id":487},"common-mistakes",[489],{"type":69,"value":490},"Common mistakes",{"type":60,"tag":249,"props":492,"children":493},{},[494,504,514,524,540],{"type":60,"tag":197,"props":495,"children":496},{},[497,502],{"type":60,"tag":65,"props":498,"children":499},{},[500],{"type":69,"value":501},"No alert on the DLQ.",{"type":69,"value":503}," A DLQ nobody watches is a slower way of losing messages.",{"type":60,"tag":197,"props":505,"children":506},{},[507,512],{"type":60,"tag":65,"props":508,"children":509},{},[510],{"type":69,"value":511},"DLQ retention shorter than your response time.",{"type":69,"value":513}," SQS keeps messages for up to 14 days. Make sure the retention covers a long weekend.",{"type":60,"tag":197,"props":515,"children":516},{},[517,522],{"type":60,"tag":65,"props":518,"children":519},{},[520],{"type":69,"value":521},"Redriving before fixing the cause.",{"type":69,"value":523}," The messages fail again and go straight back.",{"type":60,"tag":197,"props":525,"children":526},{},[527,532,534,539],{"type":60,"tag":65,"props":528,"children":529},{},[530],{"type":69,"value":531},"Non-idempotent consumers.",{"type":69,"value":533}," A message in the DLQ may have been partly processed. Replaying it must be safe. See ",{"type":60,"tag":213,"props":535,"children":536},{"href":39},[537],{"type":69,"value":538},"idempotency",{"type":69,"value":219},{"type":60,"tag":197,"props":541,"children":542},{},[543,548],{"type":60,"tag":65,"props":544,"children":545},{},[546],{"type":69,"value":547},"Retrying errors that will never succeed.",{"type":69,"value":549}," Send obviously invalid messages, such as unparseable payloads, to the DLQ immediately instead of burning retries on them.",{"type":60,"tag":551,"props":552,"children":553},"style",{},[554],{"type":69,"value":555},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":7,"searchDepth":113,"depth":113,"links":557},[558,559,560,561,562],{"id":188,"depth":98,"text":191},{"id":244,"depth":98,"text":247},{"id":294,"depth":98,"text":297},{"id":400,"depth":98,"text":403},{"id":487,"depth":98,"text":490},"markdown","content:glossary:dead-letter-queue.md","content","glossary/dead-letter-queue.md","glossary/dead-letter-queue","md",{"loc":4},1793199806797]