fix(lotus): explain a failed voice connection and offer Try again

"Failed to connect to Livekit server (Reason: ServerUnreachable)" left a
user with nothing to try; they retried for a long time and gave up.

- Title "Couldn't connect to voice". The message depends on the reason:
  unreachable/timeout-style errors explain that voice needs its own live
  connection, which VPNs, antivirus web shields and some networks block,
  even when chat works, and say what to try; NotAllowed says the call may
  be full or access changed.
- The raw reason, status and message move under Technical details.
- LivekitConnectionError and PeerConnectionTimeoutError now get a
  Try again button (the existing reconnect path), shown as primary: the
  Lotus theme renders `secondary` as dark-on-dark.

Verified in the Lotus client against a local LiveKit with the signal
socket and validate request blocked: the dialog appears after ~20 s;
unblocking and pressing Try again joins with the mic published.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
Lotus CI
2026-09-23 20:51:43 -04:00
co-authored by Claude Opus 5.5
parent e9723a21b5
commit 3e69a18a39
5 changed files with 214 additions and 75 deletions
@@ -135,7 +135,7 @@ exports[`ConnectionLostError: Action handling should reset error state 1`] = `
</p>
<button
class="_button_1nw83_8"
data-kind="secondary"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
@@ -158,7 +158,7 @@ exports[`ConnectionLostError: Action handling should reset error state 1`] = `
</DocumentFragment>
`;
exports[`LiveKit ConnectionError variants > should display LiveKit 'internal' error correctly 1`] = `
exports[`LiveKit ConnectionError variants > should explain the LiveKit 'internal' error and offer a retry 1`] = `
<DocumentFragment>
<div
class="_page_4be5c0"
@@ -286,19 +286,35 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'internal' er
<h1
class="_typography_6v6n8_153 _font-heading-md-semibold_6v6n8_112"
>
Failed to connect to Livekit server
Couldn’t connect to voice
</h1>
<p>
An error occurred while connecting to the Livekit server (
<b>
Reason:
</b>
<code>
InternalError
</code>
).
Your device couldn’t reach the voice server. Chat can still work when this happens: voice needs its own live connection, which VPNs, antivirus web protection and some work or school networks block. Try again. If it keeps failing, pause your VPN or antivirus web shield, or try another network such as a phone hotspot.
</p>
<details
class="_technicalDetails_a69dc5"
>
<summary
class="_technicalDetailsSummary_a69dc5"
>
Technical details
</summary>
<pre
class="_technicalDetailsPre_a69dc5"
>
Reason: InternalError
Internal server error
</pre>
</details>
<button
class="_button_1nw83_8"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
Try again
</button>
<button
class="_button_1nw83_8"
data-kind="tertiary"
@@ -315,7 +331,7 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'internal' er
</DocumentFragment>
`;
exports[`LiveKit ConnectionError variants > should display LiveKit 'notAllowed' error correctly 1`] = `
exports[`LiveKit ConnectionError variants > should explain the LiveKit 'notAllowed' error and offer a retry 1`] = `
<DocumentFragment>
<div
class="_page_4be5c0"
@@ -443,19 +459,36 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'notAllowed'
<h1
class="_typography_6v6n8_153 _font-heading-md-semibold_6v6n8_112"
>
Failed to connect to Livekit server
Couldn’t connect to voice
</h1>
<p>
An error occurred while connecting to the Livekit server (
<b>
Reason:
</b>
<code>
NotAllowed
</code>
).
The voice server didn’t let you in. The call may be full, or your access to this room may have changed. Try again in a moment.
</p>
<details
class="_technicalDetails_a69dc5"
>
<summary
class="_technicalDetailsSummary_a69dc5"
>
Technical details
</summary>
<pre
class="_technicalDetailsPre_a69dc5"
>
Reason: NotAllowed
Status: 403
Permission denied by server
</pre>
</details>
<button
class="_button_1nw83_8"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
Try again
</button>
<button
class="_button_1nw83_8"
data-kind="tertiary"
@@ -472,7 +505,7 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'notAllowed'
</DocumentFragment>
`;
exports[`LiveKit ConnectionError variants > should display LiveKit 'serverUnreachable' error correctly 1`] = `
exports[`LiveKit ConnectionError variants > should explain the LiveKit 'serverUnreachable' error and offer a retry 1`] = `
<DocumentFragment>
<div
class="_page_4be5c0"
@@ -600,19 +633,36 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'serverUnreac
<h1
class="_typography_6v6n8_153 _font-heading-md-semibold_6v6n8_112"
>
Failed to connect to Livekit server
Couldn’t connect to voice
</h1>
<p>
An error occurred while connecting to the Livekit server (
<b>
Reason:
</b>
<code>
ServerUnreachable
</code>
).
Your device couldn’t reach the voice server. Chat can still work when this happens: voice needs its own live connection, which VPNs, antivirus web protection and some work or school networks block. Try again. If it keeps failing, pause your VPN or antivirus web shield, or try another network such as a phone hotspot.
</p>
<details
class="_technicalDetails_a69dc5"
>
<summary
class="_technicalDetailsSummary_a69dc5"
>
Technical details
</summary>
<pre
class="_technicalDetailsPre_a69dc5"
>
Reason: ServerUnreachable
Status: 503
Server is unreachable
</pre>
</details>
<button
class="_button_1nw83_8"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
Try again
</button>
<button
class="_button_1nw83_8"
data-kind="tertiary"
@@ -629,7 +679,7 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'serverUnreac
</DocumentFragment>
`;
exports[`LiveKit ConnectionError variants > should display LiveKit 'serviceNotFound' error correctly 1`] = `
exports[`LiveKit ConnectionError variants > should explain the LiveKit 'serviceNotFound' error and offer a retry 1`] = `
<DocumentFragment>
<div
class="_page_4be5c0"
@@ -757,19 +807,35 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'serviceNotFo
<h1
class="_typography_6v6n8_153 _font-heading-md-semibold_6v6n8_112"
>
Failed to connect to Livekit server
Couldn’t connect to voice
</h1>
<p>
An error occurred while connecting to the Livekit server (
<b>
Reason:
</b>
<code>
ServiceNotFound
</code>
).
Your device couldn’t reach the voice server. Chat can still work when this happens: voice needs its own live connection, which VPNs, antivirus web protection and some work or school networks block. Try again. If it keeps failing, pause your VPN or antivirus web shield, or try another network such as a phone hotspot.
</p>
<details
class="_technicalDetails_a69dc5"
>
<summary
class="_technicalDetailsSummary_a69dc5"
>
Technical details
</summary>
<pre
class="_technicalDetailsPre_a69dc5"
>
Reason: ServiceNotFound
RTC service not found
</pre>
</details>
<button
class="_button_1nw83_8"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
Try again
</button>
<button
class="_button_1nw83_8"
data-kind="tertiary"
@@ -786,7 +852,7 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'serviceNotFo
</DocumentFragment>
`;
exports[`LiveKit ConnectionError variants > should display LiveKit 'timeout' error correctly 1`] = `
exports[`LiveKit ConnectionError variants > should explain the LiveKit 'timeout' error and offer a retry 1`] = `
<DocumentFragment>
<div
class="_page_4be5c0"
@@ -914,19 +980,35 @@ exports[`LiveKit ConnectionError variants > should display LiveKit 'timeout' err
<h1
class="_typography_6v6n8_153 _font-heading-md-semibold_6v6n8_112"
>
Failed to connect to Livekit server
Couldn’t connect to voice
</h1>
<p>
An error occurred while connecting to the Livekit server (
<b>
Reason:
</b>
<code>
Timeout
</code>
).
Your device couldn’t reach the voice server. Chat can still work when this happens: voice needs its own live connection, which VPNs, antivirus web protection and some work or school networks block. Try again. If it keeps failing, pause your VPN or antivirus web shield, or try another network such as a phone hotspot.
</p>
<details
class="_technicalDetails_a69dc5"
>
<summary
class="_technicalDetailsSummary_a69dc5"
>
Technical details
</summary>
<pre
class="_technicalDetailsPre_a69dc5"
>
Reason: Timeout
Connection timed out
</pre>
</details>
<button
class="_button_1nw83_8"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
Try again
</button>
<button
class="_button_1nw83_8"
data-kind="tertiary"
@@ -1084,6 +1166,15 @@ exports[`LiveKit ConnectionError variants > should link to troubleshoot guide wh
</a>
or contact your server administrator.
</p>
<button
class="_button_1nw83_8"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"
>
Try again
</button>
<button
class="_button_1nw83_8"
data-kind="tertiary"
@@ -1697,7 +1788,7 @@ exports[`should report correct error for 'Connection lost' 1`] = `
</p>
<button
class="_button_1nw83_8"
data-kind="secondary"
data-kind="primary"
data-size="lg"
role="button"
tabindex="0"