Repository navigation
[Bug]: Unable to link mac to iphone #4921
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
apps/desktop
Steps to reproduce
Title
[Bug]: iOS app authenticates successfully then aborts the WebSocket ~150ms after server.getConfig, infinite reconnect loop (web UI works over identical transport)
Environment
- Desktop app / server: v0.0.31 (latest release), macOS (Darwin 25.5.0), arm64
- iOS app: v0.1.0
- Transport: Tailscale tailnet, plain HTTP to
http://<tailnet-ip>:3773 - Server exposure:
serverExposureMode: "network-accessible", bound0.0.0.0:3773 - Server capabilities:
{repositoryIdentity: true, connectionProbe: true, threadSettlement: true, threadSnooze: true, serverSelfUpdate: "desktop-managed"}
Symptom
The iOS app shows Failed to connect. Reconnecting… Reason: <LABEL> connection failed unexpectedly in an
infinite retry loop, roughly every 2–16 seconds.
Server-side, every step of authentication and the WebSocket upgrade succeeds. The app issues its first
RPC (server.getConfig), the server answers it successfully, and then the client closes the socket
~130–160ms later.
Server span timeline (repeats identically on every retry)
12:59:47.029 Success SessionStore.verify
12:59:47.030 Success EnvironmentAuth.issueWebSocketTicket
12:59:47.079 Success EnvironmentAuth.authenticateWebSocketUpgrade
12:59:47.079 Success SessionStore.verifyWebSocketToken
12:59:47.081 Success SessionStore.markConnected
12:59:47.101 Success ws.rpc.server.getConfig <-- server answers the client's first RPC
12:59:47.238 Success SessionStore.markDisconnected <-- client hangs up, 157ms later
Four consecutive cycles captured at 12:59:14.7, 12:59:15.9, 12:59:18.1, 12:59:22.4, 12:59:30.7, 12:59:47.0 —
all with the same shape. No span in the window exits Failure. No requireScope failure.
Secondary observation: two isolated EnvironmentAuth.authenticateWebSocketUpgrade → Failure
(ServerAuthMissingCredentialError) at 12:59:22.872 and 12:59:39.868, interleaved with the successful
cycles. These may be the client retrying with an expired/stale WebSocket ticket.
What this is NOT (all ruled out by testing)
- Not the network / Tailscale.
GET http://<tailnet-ip>:3773/.well-known/t3/environmentreturns 200 with
the correct environment descriptor. - Not authentication or the pairing token. All auth spans succeed.
markConnectedis reached every time. - Not scheme confusion. Using
https://against the plain-HTTP port 3773 produces a distinct, earlier
failure (tlsv1 alert protocol version). This report is withhttp://, which gets much further. - Not manual-entry-specific — this rules out [Bug]: iOS app local network manual connect: Failed to fetch remote environment endpoint #4893. Pairing via the in-app QR scanner produces the
identical failure signature. [Bug]: iOS app local network manual connect: Failed to fetch remote environment endpoint #4893's workaround (scan the QR instead of typing the host) does not help. - Not [Bug]: iOS app fails to open a thread on slow links ("syncing → failed to connect") after an image Read — server inlines full base64 images into thread activity payloads #4595. That issue's mechanism is a ~5s client sync watchdog timing out on multi-megabyte payloads
over a slow link. Here the abort is at ~150ms on a LAN/tailnet. - Not the server or the transport. The web UI works fine — browsing to
http://<tailnet-ip>:3773from Safari on the same iPhone pairs successfully and stays connected,
against the same server, same port, same plain-HTTP transport. Only the native iOS client fails.
Reproduction
- macOS desktop app v0.0.31, Settings → Connections → Network access enabled.
- From an iPhone on the same tailnet, confirm
http://<tailnet-ip>:3773loads and pairs in Safari. - In the iOS app v0.1.0 → Add Environment, pair with
http://<tailnet-ip>:3773— either by typing the
host + pairing code, or by scanning the QR from a/pair#token=...link. - The environment is added and its label resolves correctly (so the HTTP probe works), then it enters the
Failed to connect. Reconnecting…loop.
Suspected cause
The iOS client appears to reject the server.getConfig response payload from server 0.0.31 — a schema or
protocol-compatibility mismatch — and closes the socket rather than surfacing a decode error. The
user-facing message (connection failed unexpectedly) gives no indication that the connection actually
succeeded and the failure was in response handling.
Ask
- Is there a known protocol-compatibility gap between iOS v0.1.0 and server 0.0.31?
- Could the client surface the actual decode/validation error instead of
connection failed unexpectedly?
A client-side close after a successful RPC is currently indistinguishable from a network failure. - Happy to capture the
server.getConfigpayload or full client logs if you can point me at how to
enable verbose logging in the iOS build.
Expected behavior
should be able to pair ios native app with the desktop macos version
Actual behavior
unable to pair, from the t3 ios app it just shows connection failed unexpectedly
Impact
Major degradation or frequent failure
Version or commit
No response
Environment
No response
Logs or stack traces
Screenshots, recordings, or supporting files
No response
Workaround
No response
Activity
Zeus-Deus commentedon Jul 30, 2026
Additional observation from an iOS client using T3 Connect against server
0.0.31:Before force-closing the iOS app, repeated attempts had the same server-side sequence described here:
SessionStore.markConnectedsucceeded.ws.rpc.server.getConfigsucceeded.connection failed unexpectedlyretry loop.Refreshing the environment, toggling it off/on, restarting the server, and reprovisioning the managed endpoint did not clear the loop. The relay and public endpoint were independently healthy.
After fully force-closing the native iOS app and reopening it, the connection succeeded. A subsequent server trace completed authentication and
server.getConfigwithout the immediate disconnect.This suggests there may also be stale in-memory client state after initial sign-in/linking or after an endpoint changes. Force-closing and reopening the iOS app is a useful workaround to document. This observation does not establish the root cause or rule out protocol/schema compatibility issues; it only shows that, in this instance, restarting the native app cleared the failure state.
godcclike commentedon Jul 30, 2026
thanks @Zeus-Deus it works after force-closing and opening again