You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Android drops a direct environment with "stopped responding" when the server config snapshot is large (~1 MB+) #23731
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/mobile
Steps to reproduce
Run a t3 serve 0.1.0 environment with several provider instances (6 Claude/Codex instances plus OpenCode with an OpenRouter catalog of ~466 models) and agents working across many folders.
Pair the Android app (store build 2.0.0, OTA current on 2026-10-22) over a direct Tailscale route.
Open the environment on mobile data.
Expected behavior
The environment connects and stays connected.
Actual behavior
The socket opens, the client sends subscribeServerConfig, receives the snapshot, then never sends another RPC. About 20 s later it closes and shows "Failed to connect. Reconnecting… Reason: stopped responding." It reconnects and drops again in a loop (28 cycles in 15 minutes in our server traces).
The server answers Ping in ~2 ms, before and after the snapshot, both on loopback and through its Tailscale HTTPS address.
The network path is not the bottleneck: 1 MB reached the phone over the same route in 3.6 s.
With the snapshot at 0.9 MB the loop continued. Disabling the OpenCode instance (snapshot 0.57 MB) let the phone connect and stay connected.
The same snapshot decodes without error against packages/contractsServerConfigStreamEvent on current main, so this is not a schema mismatch.
A second 0.1.0 environment with a small provider list connects fine from the same phone at the same time.
This looks like the client blocking while it processes a large config snapshot, long enough for the 15 s PING_TIMEOUT in packages/client-runtime/src/rpc/protocol.ts to fire. The same environment held a 15-minute connection earlier the same morning, before the phone picked up a newer OTA.
Impact
Major degradation: the environment is unusable from the phone.
Version or commit
Server 0.1.0; Android app 2.0.0 with OTA from main as of 2026-10-22.
Environment
Android 16 (Samsung S25 Ultra), direct route over Tailscale, mobile data. Server on macOS (arm64).
Logs or stack traces
Server trace, one cycle (okhttp/5.4.0):
GET /ws -> 101, lasted 13–45 s
ws.rpc.subscribeServerConfig -> Interrupted ("All fibers interrupted without error") when the socket closed
no other ws.rpc.* spans in the session
Workaround
Restart the server to clear workspaceSnapshots and shrink provider model lists (OpenCode provider.openrouter.whitelist). Both only buy time while #21181 is open.
Same loop on iOS (app 2.1.0, host 0.1.4-nightly.20261028.3822, Linux) over an in-flight satellite link, direct Tailscale route, ~800 ms RTT, ~20% loss.
Server trace per attempt: GET /ws 101, auth ok, ws.rpc.subscribeServerConfig starts, no other ws.rpc.* span, socket closes ~42 s later, subscription exits Interrupted. The app reports "stopped responding for 15s" with the host version already populated, so the socket was live and data was flowing.
Measured with a read-only web client on the same server: the snapshot is 283 KB, then a full providerStatuses list of ~260 KB on each provider status change (#21178). Tailscale's per-peer counter shows ~3.6 MB to the phone per attempt, consistent with the connect-time burst arriving uncompressed on iOS (#21183).
So the trigger is PING_TIMEOUT (15 s, packages/client-runtime/src/rpc/protocol.ts) firing while the pong sits behind multiple hundred-KB messages on a slow socket. Two fixes would each resolve it independent of payload size: reset the liveness timer on any received frame or bytes rather than on a pong, or start the ping deadline only after the initial snapshot completes. Attempts earlier on the same link, when loss was lower, connected and stayed up for minutes.
Activity
Nelglor commentedon Oct 29, 2026
Note
🤖 Claude Fable 5.1 responding on behalf of Nick
Same loop on iOS (app 2.1.0, host 0.1.4-nightly.20261028.3822, Linux) over an in-flight satellite link, direct Tailscale route, ~800 ms RTT, ~20% loss.
Server trace per attempt:
GET /ws101, auth ok,ws.rpc.subscribeServerConfigstarts, no otherws.rpc.*span, socket closes ~42 s later, subscription exits Interrupted. The app reports "stopped responding for 15s" with the host version already populated, so the socket was live and data was flowing.Measured with a read-only web client on the same server: the snapshot is 283 KB, then a full
providerStatuseslist of ~260 KB on each provider status change (#21178). Tailscale's per-peer counter shows ~3.6 MB to the phone per attempt, consistent with the connect-time burst arriving uncompressed on iOS (#21183).So the trigger is
PING_TIMEOUT(15 s,packages/client-runtime/src/rpc/protocol.ts) firing while the pong sits behind multiple hundred-KB messages on a slow socket. Two fixes would each resolve it independent of payload size: reset the liveness timer on any received frame or bytes rather than on a pong, or start the ping deadline only after the initial snapshot completes. Attempts earlier on the same link, when loss was lower, connected and stayed up for minutes.