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 <request-id>' to approve this device.
  Alternatively, access the Control UI from the server's localhost to approve.
This commit is contained in:
spiceoogway 2026-01-30 08:38:02 -05:00
parent 3aa6d0503d
commit d2c1fd3c61
2 changed files with 19 additions and 4 deletions

View File

@ -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");

View File

@ -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);
});
}