openclaw - 💡(How to fix) Fix Android UI/operator WebSocket closes silently (code=1000 bye, handshake pending) after successful node pair on v2026.5.22-dev

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

On a fresh Android pair via Tailscale Serve, the device pair auto-approves, the node pair manually approves, and node.event round-trips succeed — but the Android UI/operator WebSocket connection closes with handshake:pending, durationMs:140, code=1000, reason=bye on every retry. The app sits on "Connecting…" forever. No client- or server-side error message indicates why the handshake aborts.

Error Message

On a fresh Android pair via Tailscale Serve, the device pair auto-approves, the node pair manually approves, and node.event round-trips succeed — but the Android UI/operator WebSocket connection closes with handshake:pending, durationMs:140, code=1000, reason=bye on every retry. The app sits on "Connecting…" forever. No client- or server-side error message indicates why the handshake aborts. The operator WebSocket closes after ~140 ms with code=1000 reason=bye on every retry. App stuck in "Connecting…" loop indefinitely. No actionable error surfaced to either side.

Root Cause

On a fresh Android pair via Tailscale Serve, the device pair auto-approves, the node pair manually approves, and node.event round-trips succeed — but the Android UI/operator WebSocket connection closes with handshake:pending, durationMs:140, code=1000, reason=bye on every retry. The app sits on "Connecting…" forever. No client- or server-side error message indicates why the handshake aborts.

Fix Action

Fix / Workaround

Workarounds tried (none fully fix)

  • gateway.trustedProxies = ["127.0.0.1","::1"] — required for any proxy path including Tailscale Serve (fixed an earlier "untrusted address" reject).
  • Hand-editing paired.json to grant operator.pairing as 4th scope to Android — silenced scope_mismatch but didn't fix handshake close.
  • adb shell pm clear to defeat Android Auto Backup restoring stale bootstrap tokens.
  • Wiping all pair state + re-pairing fresh.
  • Multiple gateway restarts (each restart blocks for ~3 min on provider auth state pre-warmed in ~175000ms, blocking the Node event loop for ~136 s — separate concern but worth flagging).

Code Example

"device pairing auto-approved device=a49433945e... role=node"
"⇄ res ✓ node.pair.approve 7756ms ..."
"⇄ res ✓ node.event 125ms ..."           ← node channel works
"closed before connect conn=ff3f775e... peer=127.0.0.1:61006->127.0.0.1:18789 remote=127.0.0.1 fwd=100.71.39.50 origin=n/a host=laptop-nsq8gimm.tail9b64ff.ts.net ua=okhttp/5.3.2 code=1000 reason=bye"   ← operator channel
RAW_BUFFERClick to expand / collapse

Android UI/operator WebSocket handshake closes silently after successful node pair on v2026.5.22-dev

Summary

On a fresh Android pair via Tailscale Serve, the device pair auto-approves, the node pair manually approves, and node.event round-trips succeed — but the Android UI/operator WebSocket connection closes with handshake:pending, durationMs:140, code=1000, reason=bye on every retry. The app sits on "Connecting…" forever. No client- or server-side error message indicates why the handshake aborts.

Environment

  • Android app: 2026.5.22-dev (built from main HEAD via pnpm android:install on 2026-05-24)
  • Gateway: 2026.5.22 (commit acf265d, built from same main via pnpm build + npm install -g .)
  • Device: Samsung SM-S711B, Android 16 (SDK 36)
  • Host: Windows 11 26200, Node 24.15.0
  • Transport: Tailscale Serve (https://laptop-nsq8gimm.tail9b64ff.ts.nethttp://127.0.0.1:18789), Let's Encrypt cert, gateway.tailscale.mode=serve + gateway.bind=loopback
  • PublicURL (hardcoded — qr command failed to auto-resolve MagicDNS on Windows): wss://laptop-nsq8gimm.tail9b64ff.ts.net set in plugins.entries.device-pair.config.publicUrl

Steps to reproduce

  1. Cold-built gateway from main, configured Tailscale Serve and hardcoded publicUrl (above).
  2. adb shell pm clear ai.openclaw.app (necessary — Android Auto Backup restores stale bootstrap tokens after Settings → Clear storage).
  3. Wiped ~/.openclaw/{devices,nodes}/{paired,pending}.json to {}, restarted gateway.
  4. openclaw qr → scanned with fresh Android install.
  5. Gateway log shows device pairing auto-approved device=<id> role=node.
  6. openclaw nodes pending shows the request, openclaw nodes approve <id> succeeds (res ✓ node.pair.approve).
  7. Android node.event calls succeed (res ✓ node.event 125ms etc.).
  8. Android UI/operator channel attempts WebSocket connection every ~8 s — every attempt closes with code=1000 reason=bye after ~140 ms.

Gateway log (sanitized)

"device pairing auto-approved device=a49433945e... role=node"
"⇄ res ✓ node.pair.approve 7756ms ..."
"⇄ res ✓ node.event 125ms ..."           ← node channel works
"closed before connect conn=ff3f775e... peer=127.0.0.1:61006->127.0.0.1:18789 remote=127.0.0.1 fwd=100.71.39.50 origin=n/a host=laptop-nsq8gimm.tail9b64ff.ts.net ua=okhttp/5.3.2 code=1000 reason=bye"   ← operator channel

Earlier (before hand-editing scopes), the operator path returned reason=scope_mismatch (scopes=4). The Android device pair entry only granted 3 scopes (operator.{approvals,read,write}); I hand-edited ~/.openclaw/devices/paired.json to add operator.pairing as a 4th scope. After this, scope_mismatch went away but the handshake still closes silently.

Structured handshake event has handshake:"pending" (i.e. server never saw the auth/connect frame) before close.

Android logcat

  • App emits OpenClawGateway: node.event failed: IllegalStateException repeatedly (no stack trace surfaced beyond W level).
  • okhttp3 connect plan retries every ~8 seconds (StrictMode noise only).
  • No OkHttp onFailure, HandshakeException, SSLException, or connectFailed logged.

Expected

After a successful node pair, the Android UI/operator WebSocket should complete handshake and the app should reach Ready.

Actual

The operator WebSocket closes after ~140 ms with code=1000 reason=bye on every retry. App stuck in "Connecting…" loop indefinitely. No actionable error surfaced to either side.

Workarounds tried (none fully fix)

  • gateway.trustedProxies = ["127.0.0.1","::1"] — required for any proxy path including Tailscale Serve (fixed an earlier "untrusted address" reject).
  • Hand-editing paired.json to grant operator.pairing as 4th scope to Android — silenced scope_mismatch but didn't fix handshake close.
  • adb shell pm clear to defeat Android Auto Backup restoring stale bootstrap tokens.
  • Wiping all pair state + re-pairing fresh.
  • Multiple gateway restarts (each restart blocks for ~3 min on provider auth state pre-warmed in ~175000ms, blocking the Node event loop for ~136 s — separate concern but worth flagging).

Asks

  1. What additional client/server diagnostic would help isolate where the operator handshake aborts? Is there a way to enable verbose WS frame logging?
  2. Should operator.pairing be auto-granted by the device-pair flow when the Android client requests scopes=4? Currently the device entry only grants 3 scopes, and the 4th scope it requests is rejected.
  3. Is the gateway expected to honor a hand-edited paired.json scope set, or does some in-memory cache override it after restart? (Observed CLI device entry being silently reset to operator.pairing only.)
  4. Any guidance on the Auto Backup behavior — recommend disabling allowBackup in the manifest so users get a true fresh state on reinstall?

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Android UI/operator WebSocket closes silently (code=1000 bye, handshake pending) after successful node pair on v2026.5.22-dev