Fix CreditResponse (0x8009) decode crashing the connection - #22
Open
mjquinlan2000 wants to merge 2 commits into
Open
Fix CreditResponse (0x8009) decode crashing the connection#22mjquinlan2000 wants to merge 2 commits into
mjquinlan2000 wants to merge 2 commits into
Conversation
The decoder listed :credit among correlated responses and tried to read a 4-byte correlation_id, but CreditResponse has none (code + subscription_id only), raising MatchError and crashing the connection. Decode it directly.
Wrap per-frame Decoder.decode in try/rescue: log and drop a frame that fails to decode instead of crashing the connection GenServer. Defense in depth so no single unexpected frame can take down the stream pipeline.
VictorGaiva
approved these changes
Jul 22, 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.
Problem
RabbitMQStream.Message.Decoderlists:creditamong the correlated responses, so it decodes aCreditResponseby readingcorrelation_id::32, code::16(6 bytes). But aCreditResponsehas no correlation id — its body isresponse_code::16, subscription_id::8(3 bytes). Decoding one therefore raisesMatchError, and becauseBuffer.parse_frames/2callsDecoder.decode/1directly inside the connectionGenServer'shandle_infowith no rescue, that single frame crashes the whole connection.The broker sends a
CreditResponseonly on error — e.g. crediting a subscription it no longer knows about — which happens routinely during single-active-consumer rebalancing and after a reconnect. In production this crash-looped a consumer under load (each reconnect re-hit the frame).Protocol references
Per the RabbitMQ streams protocol spec —
deps/rabbitmq_stream/docs/PROTOCOL.adoc:Creditis not a correlated command — the request carries aSubscriptionId, not aCorrelationId:And the response has no
CorrelationId— only a response code and subscription id:The spec also notes the response is an error-only signal:
A real frame seen in production was
<<0,0,0,7, 0x80,0x09, 0,1, 0x00,0x11, 0x07>>— length 7, key0x8009, version 1,ResponseCode = 0x0011(precondition_failed),SubscriptionId = 7. The correlated-response clause tried to read a 4-byte correlation id from the 3-byte body →MatchError.Fix
:creditdecode/2clause readscode::16, subscription_id::8(no correlation id) and returns the existing%Types.CreditResponseData{};:creditis removed from the correlated-response clause's command list.Buffer.parse_frames/2wraps the per-frameDecoder.decode/1intry/rescue: an undecodable frame is logged (Logger.warning) and skipped instead of crashing the connection process. This keeps a single malformed/unexpected frame from taking down the whole connection.Tests
Adds an offline
test/message/decoder_test.exs(no broker required):CreditResponsebytes decode to%Response{command: :credit, code: :precondition_failed}withcorrelation_id: nilanddata: %Types.CreditResponseData{}.parse_frames/2drops an unknown/undecodable frame while a valid frame in the same batch still decodes.The existing broker-tagged integration tests are unaffected.