Skip to content

MassTransit interop keeps the inbox id of a durable envelope when it reads the messageId - #5398

Merged
jeremydmiller merged 2 commits into
mainfrom
masstransit-keep-inbox-id
Nov 6, 2026
Merged

jeremydmiller merged 2 commits into
mainfrom
masstransit-keep-inbox-id

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

The bug

MassTransitEnvelope.TransferData always replaced Envelope.Id with the MassTransit messageId. It runs from MassTransitJsonSerializer.ReadFromData, when the handler pipeline deserializes the body, which is after the durable inbox has already stored the envelope.

On Amazon SQS the MassTransit mapper (MassTransitMapper.ReadEnvelopeData) sets neither the id nor the message type. The listener derives the id from the SQS message, and the durable inbox stores the envelope under that id. Then:

  1. The handler runs with Envelope.Id = the MassTransit messageId.
  2. Mark-handled, the scheduled retry and the move to dead letters key on that id and match no row.
  3. The inbox row stays Incoming and is run again on recovery.

Reproduced against LocalStack with a PostgreSQL inbox, using ListenToSqsQueue(...).UseMassTransitInterop().DefaultIncomingMessage<T>().UseDurableInbox() and a raw MassTransit body. The handler saw the MassTransit id, and the inbox row (stored under the SQS-derived id) was still Incoming 15 seconds after the handler finished.

This is the same shape as the CloudEvents case in #5396.

The fix

TransferData leaves Envelope.Id alone when the envelope WasPersistedInInbox. A non-persisted envelope still takes the MassTransit messageId, and the correlation id, conversation id, headers, expiration and sent time are transferred as before.

RabbitMQ and Azure Service Bus read the envelope id from the broker's own message id, which MassTransit sets to the same Guid as messageId, so they were not affected in practice (from reading the code; not probed).

Tests

  • CoreTests MassTransitEnvelopeTests.an_envelope_held_in_the_inbox_keeps_the_id_it_was_stored_under
  • Wolverine.AmazonSqs.Tests masstransit_interop_with_durable_inbox_keeps_inbox_id: SQS (LocalStack) + PostgreSQL inbox, asserting the row is not left Incoming after the handler succeeds

Both fail without the fix and pass with it. Also run locally: the CoreTests Runtime.Interop tests, the RabbitMQ MassTransit tests, and dotnet build wolverine.slnx -c Release -f net9.0. After rebasing onto current main, the CoreTests interop tests were rerun (59 green). The SQS test was built but not rerun after the rebase, because the local containers were down.

🤖 Generated with Claude Code

jeremydmiller and others added 2 commits November 6, 2026 07:03
…reads the messageId

MassTransitEnvelope.TransferData always replaced Envelope.Id with the MassTransit
messageId when the handler pipeline deserialized the body. On SQS the MassTransit
mapper leaves the id to the listener, which derives it from the SQS message, and
the durable inbox stores the envelope under that id. Mark-handled, retry and
dead-letter then matched no row, so the inbox row stayed Incoming and ran again
on recovery. Same shape as the CloudEvents case in #5396.

TransferData now leaves the id alone for an envelope that WasPersistedInInbox.
Tests: CoreTests unit test, and an SQS (LocalStack) + PostgreSQL inbox test that
fails without the fix with the row left Incoming.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sts are not MediatorOnly

The GH-5391 test runs `codegen test` / `codegen write` through RunJasperFxCommands,
which leaves the process-wide DynamicCodeBuilder.WithinCodegenCommand flag set.
applyMetadataOnlyModeIfDetected then starts every later host in that test process
in MediatorOnly mode, so whichever CoreTests ran after it in the same worker failed
("This operation is not allowed with Wolverine is bootstrapped in MediatorOnly
mode") -- red on main at 6.62.1, green at a89e663, depending only on test order.

Reset the flag after the commands and in finally, and run the class in a
non-parallel collection so no host starts while the flag is set (the same
arrangement Wolverine.Grpc.Tests uses for this flag).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jeremydmiller
jeremydmiller merged commit 14b34d5 into main Nov 6, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant