Repository navigation
GH-4595: stop the protocol version header surviving a round trip - #4599
Merged
Merged
Conversation
writeIncomingHeaders copies every wire header into Envelope.Headers, so an envelope received from Redis or Kafka carried wolverine-protocol-version as a header of its own. MapEnvelopeToOutgoing stamps its own copy on every send, so re-sending that envelope -- the dead letter sender path under BufferedInMemory or Durable listening, most visibly -- wrote the field twice. A dictionary-shaped outgoing header set silently collapsed the two; Redis (List<NameValueEntry>) and Kafka (Headers) both accept the same name twice, so the entry landed malformed and any consumer reading it into a keyed structure threw. Fixed centrally in MapIncomingToEnvelope rather than per transport: nothing reads the protocol version off Envelope.Headers, it is plumbing the outgoing mapper re-stamps, and every mapper that copies headers wholesale has the same exposure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDUrBeB4tTnKj4AExCS1nj
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.
Closes #4595.
RedisEnvelopeMapperwrotewolverine-wolverine-protocol-versiontwice whenever it re-sent an envelope it had received. The round trip is the cause, not the Redis mapper:writeIncomingHeaderscopies every wire header intoEnvelope.Headers, so the received envelope keptwolverine-protocol-versionas a header of its own, andMapEnvelopeToOutgoingstamps its own copy onto every send. Second pass, two fields with the same name.Where it bites
Redis's outgoing headers are a
List<NameValueEntry>and Kafka's are aHeaderslist — both accept the same name twice. Everywhere else the outgoing headers are a dictionary, so the second write collapsed onto the first and nothing showed. So the visible damage is a malformed stream entry, most easily reached through the native dead letter queue underBufferedInMemoryorDurablelistening (those route the failure throughTryBuildDeadLetterSender→ the mapper, rather than throughRedisStreamListener.MoveToErrorsAsync, which writes its fields explicitly). A consumer reading that entry into a keyed structure throws:This is latent on
mainonly because the RedisDeadLetterQueueTestscurrently listen Inline. It surfaced in CI on #4506, which is not its cause.The fix
One line, in
EnvelopeMapper.MapIncomingToEnvelope: drop the protocol version fromEnvelope.Headersas the envelope comes in.Central rather than per-transport, because the exposure is not Redis's. Nothing in the codebase reads the protocol version off
Envelope.Headers— it is plumbing that the outgoing mapper re-stamps on every send — and every mapper that copies wire headers wholesale keeps it. Kafka had the identical duplicate; the test proves both.Tests
envelope_mapper_round_trip_4595in each of the Redis and Kafka test suites. No broker: they map an envelope out, read it back, and map it out again, exactly as the dead letter sender does. Red before the change (3 of 4 Redis, 2 of 2 Kafka), green after, and red again with the one line commented out.Clean
dotnet build wolverine.slnx -c Release -f net9.0.Not fixed here
The issue's closing observation stands and is worth its own issue: the two Redis dead-letter paths write different field shapes —
MoveToErrorsAsyncwritesexception-type/exception-message/failed-atand friends, the dead letter sender path writes mapper-shapedwolverine-*fields. Whether native dead letter metadata should depend on the listener mode at all is the larger question behind this bug, and is not something to settle inside a one-line fix.🤖 Generated with Claude Code
https://claude.ai/code/session_01VDUrBeB4tTnKj4AExCS1nj