During a homeserver stall the call widget's delayed-event restarts pile up in the host (burst of 404/429 on recovery), and the host keeps showing "in call" after Element Call reports Connection lost #318

Closed
opened 2026-10-05 16:17:02 -04:00 by jared · 0 comments
Owner

The host half of element-call#46.

Request pile-up. CallWidgetDriver.restartScheduledDelayedEvent (src/app/plugins/call/CallWidgetDriver.ts:132) awaits mx._unstable_restartScheduledDelayedEvent(delayId) with no timeout and no de-duplication. While Synapse is stalled, Element Call times out each restart locally after 2 s and sends another update_delayed_event, so the host keeps opening new HTTP requests for the same delay_id. In a 60 s stall, 12 requests were pending (each waited 22–43 s). On recovery they all hit the server together:

POST …/delayed_events/<id>/restart  404 ×5   (the delayed leave was already sent)
POST …/delayed_events/<id>/restart  429 ×7   (M_LIMIT_EXCEEDED, our own burst)

→ Fix: keep one in-flight restart per delay_id and return that promise to later callers. Also give the host request its own timeout, a little longer than the widget's 2 s local timeout, so stale requests are aborted instead of queued.

Host UI doesn't follow the call frame. After the stall, the frame shows "Connection lost · You were disconnected from the call · Reconnect". The host still shows the call as joined: the call bar with mute/deafen/screenshare, the Soundboard button and the room's live state. Those controls now do nothing, and nothing in Lotus's own UI says the call dropped.
→ Fix: have the fork report the error state (an io.lotus.call_state/controls_state field, or a dedicated action). On the host, show "Call disconnected — Reconnect" in the call bar, and offer or trigger the reconnect once SyncState is back to SYNCING.


Found in the October 2026 client audit (Playwright against a local Synapse + LiveKit stack, plus code reading). Code refs are at cinny 30e2dbcd, cinny-desktop 8f67ec7, element-call 3b0050e8.

The host half of element-call#46. **Request pile-up.** `CallWidgetDriver.restartScheduledDelayedEvent` (src/app/plugins/call/CallWidgetDriver.ts:132) awaits `mx._unstable_restartScheduledDelayedEvent(delayId)` with no timeout and no de-duplication. While Synapse is stalled, Element Call times out each restart locally after 2 s and sends another `update_delayed_event`, so the host keeps opening new HTTP requests for the same `delay_id`. In a 60 s stall, 12 requests were pending (each waited 22–43 s). On recovery they all hit the server together: ``` POST …/delayed_events/<id>/restart 404 ×5 (the delayed leave was already sent) POST …/delayed_events/<id>/restart 429 ×7 (M_LIMIT_EXCEEDED, our own burst) ``` → **Fix:** keep one in-flight restart per `delay_id` and return that promise to later callers. Also give the host request its own timeout, a little longer than the widget's 2 s local timeout, so stale requests are aborted instead of queued. **Host UI doesn't follow the call frame.** After the stall, the frame shows "Connection lost · You were disconnected from the call · Reconnect". The host still shows the call as joined: the call bar with mute/deafen/screenshare, the Soundboard button and the room's live state. Those controls now do nothing, and nothing in Lotus's own UI says the call dropped. → **Fix:** have the fork report the error state (an `io.lotus.call_state`/`controls_state` field, or a dedicated action). On the host, show "Call disconnected — Reconnect" in the call bar, and offer or trigger the reconnect once `SyncState` is back to `SYNCING`. --- _Found in the October 2026 client audit (Playwright against a local Synapse + LiveKit stack, plus code reading). Code refs are at cinny `30e2dbcd`, cinny-desktop `8f67ec7`, element-call `3b0050e8`._
jared added the bugpriority: mediumarea: calls labels 2026-10-05 16:17:02 -04:00
jared closed this issue 2026-10-19 12:42:08 -04:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#318