PROD-77638 - Prevent double-stringify of DLQ messages on catch path#75
Merged
Dimitris-Ilias merged 3 commits intoWorkable:masterfrom May 8, 2026
Conversation
Michalis-Apostolou
approved these changes
May 8, 2026
nikosd23
reviewed
May 8, 2026
nikosd23
reviewed
May 8, 2026
There was a problem hiding this comment.
Pull request overview
Fixes DLQ payload corruption when the addToDLQ catch-path republishes a message after a DLQ publish or afterDlq hook failure, preventing double-JSON-stringification and ensuring DLQ messages remain byte-identical to the original.
Changes:
encode()now short-circuits when given aBuffer, returning it unchanged.BaseQueueHandler.addToDLQcatch-path republishesmsg.content(rawBuffer) instead ofmsg.content.toString(), and improves error logging context.- Test rewritten to validate DLQ messages decode back to the original event shape at the broker boundary.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| ts/encode-decode.ts | Treat Buffer payloads as already-encoded and return them unchanged to avoid double-encoding. |
| ts/base-queue-handler.ts | Republishes raw message bytes to DLQ on catch-path to preserve payload fidelity; adds correlationId/DLQ context to error logs. |
| test/base-queue-handler.test.ts | Updates DLQ test to subscribe to the DLQ and validate round-trip decoding for messages delivered by RabbitMQ. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
nikosd23
previously approved these changes
May 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
BaseQueueHandler.addToDLQcatch-path corrupts message payloads when the primary DLQ publish orafterDlqhook fails, producing double-encoded messages on the DLQ that downstream consumers cannot decode back to their original shape.Before this PR
When a message fails repeatedly and the primary
addToDLQflow throws (e.g.afterDlqraises during transient broker instability or downstream errors), execution falls into the catch block:msg.contentis the original rawBufferof already-encoded JSON; calling.toString()yields a JSON string.rabbit.publishthen routes it throughencode()which callsJSON.stringifyagain, producing a double-encoded payload. For an original event of{"foo":1}, the DLQ ends up with"{\"foo\":1}"After this PR
msg.content(the rawBuffer) directly torabbit.publishinstead ofmsg.content.toString(). The DLQ entry is now byte-identical to the original message.encode()short-circuits onBuffer.isBuffer(message)and returns the Buffer unchanged. This honors the type contract and is what allows the catch-path to keep using the high-levelrabbit.publishAPI without dropping tochannel.sendToQueue.[correlationId]-prefixed convention used elsewhere in the file.Follow-ups
The catch-path may still publish two messages to the DLQ when
afterDlqthrows after a successful first publish (one from the try-block, one from the catch). This PR fixes the malformation but not the duplication. The new test already exercises that path and can be extended in a follow-up PR to assert deduplicated behavior.