Skip to content

Fix RabbitMQ double acknowledgement on InvokeAsync deserialization exceptions#2234

Merged
jeremydmiller merged 1 commit intomainfrom
GH2232
Feb 24, 2026
Merged

Fix RabbitMQ double acknowledgement on InvokeAsync deserialization exceptions#2234
jeremydmiller merged 1 commit intomainfrom
GH2232

Conversation

@jeremydmiller
Copy link
Member

Summary

  • Make RabbitMqEnvelope.CompleteAsync() idempotent so a second call is a no-op
  • Set Acknowledged = true before the NACK in moveToErrorQueueAsync so the subsequent CompleteAsync() from MoveToErrorQueue.ExecuteAsync() is skipped

Root Cause

MoveToErrorQueue.ExecuteAsync() calls both MoveToDeadLetterQueueAsync() (which NACKs the message) and CompleteAsync() (which ACKs it). The second ack/nack on an already-consumed delivery tag causes RabbitMQ to close the channel with PRECONDITION_FAILED - unknown delivery tag, which deletes the response queue and breaks all subsequent InvokeAsync() calls.

Test plan

🤖 Generated with Claude Code

MoveToErrorQueue.ExecuteAsync() calls both MoveToDeadLetterQueueAsync()
(which NACKs the message) and CompleteAsync() (which ACKs it). The second
ack on an already-consumed delivery tag causes RabbitMQ to close the channel
with PRECONDITION_FAILED, breaking all subsequent InvokeAsync() calls.

Fix: Make RabbitMqEnvelope.CompleteAsync() idempotent by checking the
Acknowledged flag before calling BasicAckAsync, and set Acknowledged=true
before the NACK in moveToErrorQueueAsync so the subsequent CompleteAsync
is a no-op.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

RabbitMQ double acknowledgement on InvokeAsync deserialization exceptions

1 participant