Delivery indicator gets stuck: your last message keeps "Sending..." (or "Queued" / "Failed to send") after the server has it #306
Open
opened 2026-10-04 23:44:34 -04:00 by jared
·
1 comment
No Branch/Tag Specified
lotus
fix/delivery-status-live
fix/room-upgrade-lotus-state
fix/quiet-hours-tick
fix/logout-wipe-leftovers
fix/inter-font-name
fix/dialog-enter-closes
fix/filtered-timeline-double-count
fix/retention-floor-grace
fix/firefox-persist-hang
fix/phantom-ring-after-reload
fix/local-room-names-rest
fix/missed-call-voice-rooms
fix/animated-bg-compositor
fix/link-safety-bypasses
fix/e2e-register-403
fix/local-room-names-everywhere
fix/collapsible-messages
fix/logout-volume-residue
fix/enter-newline-device-local
fix/dnd-restore-status
fix/presence-sticky
fix/location-confirm
fix/reminders-stick
fix/voice-full-distinct-users
fix/presence-pagehide-status
fix/gif-card-aspect
deps/npm-audit-fixes
security-nudge
linux-package-updates
audit-brace-expansion
server-status-banner
desktop-keychain-mirror
desktop-call-origin
clock-skew-lag
offline-outbox
desktop-lotus-links
poll-ui
calls-open-in-browser
screenshare-prompt
call-origin-split
update-packages
sw-fix
read-me-update
image-path-changes
dm-calls
fix-2469
renovate/element-hq-element-call-embedded-0.x
renovate/npm-i18next-http-backend-vulnerability
renovate/npm-vite-vulnerability
dev
docs-update
more-theme
fix-257
imporve-thread-reply
revert-2402-improve-menu-congestion
mxidColor-toggle
update-sw-main-msg
v4.11.1
v4.10.5
v4.10.4
v4.10.3
v4.10.2
v4.10.1
v4.10.0
v4.9.1
v4.9.0
v4.8.1
v4.8.0
v4.7.1
v4.7.0
v4.6.0
v4.5.1
v4.5.0
v4.4.0
v4.3.2
v4.3.0
v4.2.3
v4.2.2
v4.2.1
v4.2.0
v4.1.0
v4.0.3
v4.0.0
v3.2.0
v3.1.0
v3.0.0
v2.2.6
v2.2.5
v2.2.4
v2.2.3
v2.2.2
v2.2.1
v2.2.0
v2.1.3
v2.1.2
v2.1.1
v2.1.0
v2.0.4
v2.0.3
v2.0.2
v2.0.1
v2.0.0
v1.8.2
v1.8.1
v1.8.0
v1.7.0
v1.6.1
v1.6.0
v1.5.1
v1.5.0
v1.4.0
v1.3.2
v1.3.1
v1.3.0
v1.2.1
v1.2.0
v1.1.0
v1.0.0
Labels
Clear labels
a11y
area: appearance
area: auth-session
area: build-ci
area: calls
area: desktop
area: media
area: messaging
area: mobile
area: moderation
area: navigation
area: notifications
area: settings
area: threads
bug
dependencies
docs
duplicate
enhancement
help wanted
invalid
needs-human-review
performance
planning
priority: critical
priority: high
priority: low
priority: medium
qa
question
research
security
tech-debt
ux
wontfix
Accessibility: keyboard, screen reader, contrast, motion
Client area: appearance
Client area: auth-session
Client area: build-ci
Client area: calls
Client area: desktop
Client area: media
Client area: messaging
Client area: mobile
Client area: moderation
Client area: navigation
Client area: notifications
Client area: settings
Client area: threads
Something is not working
Third-party package versions and advisories
README / LOTUS_* docs wrong or missing
This issue or pull request already exists
New feature
Need some help
Something is wrong
Re-render storms, leaks, heavy work on hot paths
Data loss, security hole, or crash on a main path
Broken feature or serious usability problem
Minor issue or polish
Wrong behaviour in an edge case or notable degradation
Manual QA: shipped, needs a human in a real environment
More information is needed
XSS, unsafe URLs, data leaks, auth/session
Code health, dead code, fragile patterns
Usability or visual inconsistency
This won't be fixed
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: LotusGuild/cinny#306
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The delivery-status indicator on your own messages (
DeliveryStatusinsrc/app/features/room/message/Message.tsx:106, added in0897e2ce) shows whatevermEvent.statuswas the last time the timeline happened to re-render. It never re-renders when the send status changes. Nothing re-renders the row after the server confirms the message unless someone reads it, someone else posts, or you send another message. So the last message you send in a quiet room keeps a spinning "Sending..." arrow indefinitely, and it looks unsent.Repro (Playwright, local Synapse;
/senddelayed by 100 ms or 300 ms to look like a real network):The last row still has its local-echo id (
data-message-id="~!room:txn") and the "Sending..." arrow, see the screenshot. It changed only when Bob sent a read receipt or a message, or when the room was opened again. Locally, with Synapse answering in about 10 ms, the status is usuallynullalready by the time the composer re-render happens, which hides the bug in development.The same stale render produces two worse states:
handleRetrychecksmEvent.status === NOT_SENTand the status is nownull. A user who believes it is a failure will type the message again, which creates a duplicate.QUEUEDbehind the first. It kept "Queued" after both were delivered (8 s later: first "Sending...", second "Queued").Why:
RoomTimelinere-renders onRoomEvent.Timeline. A local echo's later status changes (SENDING → SENT → nullwhen the remote echo arrives,NOT_SENT→ resend →null) only emitRoomEvent.LocalEchoUpdatedandMatrixEventEvent.Status/LocalEventIdReplaced, and nothing in the timeline listens to those. This is the same root cause as the stale~id in #284.Fix: have
DeliveryStatus(and ideally the message row, fordata-message-id) subscribe to the event:mEvent.on(MatrixEventEvent.Status, …)andMatrixEventEvent.LocalEventIdReplaced, with auseStatetick. Alternatively, bump the timeline onRoomEvent.LocalEchoUpdatedfor the open room. Add a Playwright test with a delayed/sendroute that checks the last message's indicator clears within 2 s of the server response, and that a message auto-retried by the outbox no longer shows "Failed to send".Screenshot
Found in the October 2026 client audit (Playwright against a local Synapse + LiveKit stack, plus code reading). Code refs are at cinny
30e2dbcd, cinny-desktop8f67ec7, element-call3b0050e8.Realistic repro (2026-10-05): freeze the dev Synapse for 90 s (
kill -STOP), send a message during the stall, then resume (kill -CONT). The server stores the message within 1 s of resuming (one copy), but the row keeps the "Sending..." arrow for at least 21 s afterwards and only clears on the next re-render. After a real outage, users will think their last message never went out.