From d2c1fd3c61b621aa651a8fa369cfad7e47a7a853 Mon Sep 17 00:00:00 2001 From: spiceoogway Date: Fri, 30 Jan 2026 08:38:02 -0500 Subject: [PATCH] fix: improve device pairing error message for remote connections Fixes #4531 When accessing the Web UI from a different machine on the LAN, users were getting a cryptic 'disconnected (1008): pairing required' error with no indication of how to resolve it. Changes: 1. Enhanced server error message to include: - Clear explanation of the pairing requirement - Step-by-step CLI instructions (openclaw devices list/approve) - The specific request ID to approve - Note that approval must be done on the server machine - Alternative method (localhost Control UI) 2. Updated Web UI to propagate the full error message from the server instead of the generic 'connect failed' message Impact: - Non-breaking change (only improves error messaging) - Backwards compatible with existing clients - Significantly improves UX for LAN/remote access scenarios Before: Error: disconnected (1008): pairing required After: Error: Device pairing required. On the OpenClaw server machine, run: 'openclaw devices list' to see pending requests, then 'openclaw devices approve ' to approve this device. Alternatively, access the Control UI from the server's localhost to approve. --- .../server/ws-connection/message-handler.ts | 17 +++++++++++++++-- ui/src/ui/gateway.ts | 6 ++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/gateway/server/ws-connection/message-handler.ts b/src/gateway/server/ws-connection/message-handler.ts index 948d6cefb..5c91c4eb9 100644 --- a/src/gateway/server/ws-connection/message-handler.ts +++ b/src/gateway/server/ws-connection/message-handler.ts @@ -664,12 +664,25 @@ export function attachGatewayWsMessageHandler(params: { requestId: pairing.request.requestId, reason, }); + const helpMessage = + `Device pairing required. ` + + `On the OpenClaw server machine, run: ` + + `'openclaw devices list' to see pending requests, then ` + + `'openclaw devices approve ${pairing.request.requestId}' to approve this device. ` + + `Alternatively, access the Control UI from the server's localhost to approve.`; send({ type: "res", id: frame.id, ok: false, - error: errorShape(ErrorCodes.NOT_PAIRED, "pairing required", { - details: { requestId: pairing.request.requestId }, + error: errorShape(ErrorCodes.NOT_PAIRED, helpMessage, { + details: { + requestId: pairing.request.requestId, + deviceId: device.id, + instructions: { + list: "openclaw devices list", + approve: `openclaw devices approve ${pairing.request.requestId}`, + } + }, }), }); close(1008, "pairing required"); diff --git a/ui/src/ui/gateway.ts b/ui/src/ui/gateway.ts index fc8dde08a..122df9fea 100644 --- a/ui/src/ui/gateway.ts +++ b/ui/src/ui/gateway.ts @@ -219,11 +219,13 @@ export class GatewayBrowserClient { this.backoffMs = 800; this.opts.onHello?.(hello); }) - .catch(() => { + .catch((err) => { if (canFallbackToShared && deviceIdentity) { clearDeviceAuthToken({ deviceId: deviceIdentity.deviceId, role }); } - this.ws?.close(CONNECT_FAILED_CLOSE_CODE, "connect failed"); + // Extract the error message to pass to onClose handler + const errorMessage = err instanceof Error ? err.message : "connect failed"; + this.ws?.close(CONNECT_FAILED_CLOSE_CODE, errorMessage); }); }