Skip to content

[Bug]: Unable to link mac to iphone #4921

Closed

Description

@godcclike

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", bound 0.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)

  1. Not the network / Tailscale. GET http://<tailnet-ip>:3773/.well-known/t3/environment returns 200 with
    the correct environment descriptor.
  2. Not authentication or the pairing token. All auth spans succeed. markConnected is reached every time.
  3. Not scheme confusion. Using https:// against the plain-HTTP port 3773 produces a distinct, earlier
    failure (tlsv1 alert protocol version). This report is with http://, which gets much further.
  4. 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.
  5. 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.
  6. Not the server or the transport. The web UI works fine — browsing to
    http://<tailnet-ip>:3773 from 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

  1. macOS desktop app v0.0.31, Settings → Connections → Network access enabled.
  2. From an iPhone on the same tailnet, confirm http://<tailnet-ip>:3773 loads and pairs in Safari.
  3. 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.
  4. 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

  1. Is there a known protocol-compatibility gap between iOS v0.1.0 and server 0.0.31?
  2. 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.
  3. Happy to capture the server.getConfig payload 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

  1. added
    bugSomething is broken or behaving incorrectly.
    needs-triageIssue needs maintainer review and initial categorization.
    on Jul 30, 2026
  2. Zeus-Deus commented on Jul 30, 2026

    @Zeus-Deus
    Contributor

    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:

    1. WebSocket authentication succeeded.
    2. SessionStore.markConnected succeeded.
    3. ws.rpc.server.getConfig succeeded.
    4. The client disconnected roughly 0.18–0.4 seconds after the WebSocket opened.
    5. The app entered the generic connection failed unexpectedly retry 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.getConfig without 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.

  3. godcclike commented on Jul 30, 2026

    @godcclike
    Author

    thanks @Zeus-Deus it works after force-closing and opening again

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.needs-triageIssue needs maintainer review and initial categorization.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions