Skip to content

fix(chat): settle a denied send instead of offering a retry - #1760

Merged
bmc08gt merged 6 commits into
code/cashfrom
fix/chat-send-denied
Oct 12, 2026
Merged

bmc08gt merged 6 commits into
code/cashfrom
fix/chat-send-denied

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 12, 2026

Copy link
Copy Markdown
Collaborator

A SendMessage Denied left the row FAILED and retryable, so the user saw "Not Delivered. Tap to retry" for a send the server would never take. One user on 2026.10.1 produced 6 of the 18 overnight Bugsnag events this way in about 30 seconds: each Retry came back Denied, the composer stayed up, typing notices kept going to the chat, and every refusal was reported.

  • New status: MessageStatus.DENIED and DeliveryStatus.DENIED, stored by enum name, so there is no migration. The converter's fallback means an older build reads a DENIED row as SENT. Outbox and sweep queries match 'SENDING' or 'SENT', so nothing resends a DENIED row, and a late confirm still settles it as SENT.
  • Send paths: MessagingDelegate and MediaSendDelegate write DENIED on SendMessageError.Denied. The photo path drops the stored blob, as it already did for EncryptionNotAllowed.
  • Receipt: a DENIED row reads "Not Delivered. You can't post in this chat" in the error colour, always shows, and isn't tappable. MediaMessageBubble now honours MediaSendProgress.Failed.retryable, which it used to ignore, so photos that fail with EncryptionNotAllowed stop offering a retry too.
  • Re-read: on Denied, rereadAfterDenied calls GetChat and stores the result, so a changed speaker rule hides the composer. It writes through upsertKeepingMembership: the plain upsert sets is_member = 1, which put a user back in the feed when the stream's MemberLeft landed before the re-read returned. The read and the write are separate calls, so a MemberLeft landing between them can still be overwritten. The re-read runs inline: the row is already DENIED, so the UI doesn't wait, but photos queued behind it start one RPC later.
  • Reporting: SendMessageError.Denied, NotifyIsTypingError.Denied and AdvancePointerError.Denied are now UnreportedError.

A user removed from a group keeps the composer until the stream's MemberLeft arrives. GetChat doesn't return the caller's membership and Denied carries no reason, so the re-read can't tell a removal from a speaker rule. If the server also refuses GetChat to that user, the re-read's GetChatError.Denied is still reported; it's shared with chat hydration and link cards, so it isn't changed here.

The server answers Denied when it won't take a message from this user in
this chat, so a retry gets the same answer. Text and photo sends now mark
the row DENIED instead of FAILED, and the photo path drops its stored
blob as it already does for EncryptionNotAllowed.
… retry

A DENIED row now reads "Not Delivered. You can't post in this chat" in
the error colour, always shows, and isn't tappable. Photo bubbles stop
offering Retry for any failure the send path marked non-retryable; they
used to ignore that flag.
Denied carries no reason. If a speaker rule changed, the stored rules are
stale and the composer stays up; re-reading the chat lets speakerBlock
see the new rules and hide it. A removal from the group still isn't
visible, because GetChat doesn't return the caller's membership.
A denied send now settles as DENIED with its own message, and typing and
read-pointer callers already ignore the result, so these refusals no
longer need to reach Bugsnag. One user produced 6 of the 18 overnight
events this way.
ChatEntityMapper.toEntity writes is_member = 1 by default. If the stream's
MemberLeft landed before the re-read returned, the upsert put a removed
user back in the feed as a member. The re-read now keeps whatever
membership is stored.
@bmc08gt bmc08gt self-assigned this Oct 12, 2026
@github-actions github-actions Bot added type: fix Bug fix area: network gRPC, connectivity, API, exchange rates and removed type: fix Bug fix labels Oct 12, 2026
@bmc08gt
bmc08gt merged commit 19d1dbd into code/cash Oct 12, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: network gRPC, connectivity, API, exchange rates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant