← Back to PRs

#6846: fix: bridge node.pair.* tools to device pairing store

by cortexuvula open 2026-02-02 03:42 View on GitHub →
gateway
## Problem When a node connects via WebSocket for the first time, the gateway's connect handler creates a pending pairing request in the **device store** (`~/.openclaw/devices/pending.json`). However, the `node.pair.list`, `node.pair.approve`, and `node.pair.reject` handlers only check the **node store** (`~/.openclaw/nodes/`). This means: - `nodes pending` (agent tool) returns an empty list even when there are pending node pairing requests - `nodes approve` fails with `unknown requestId` because it can't find the request The only workaround is manually editing `devices/paired.json` and restarting the gateway — inaccessible for non-technical users. ## Root Cause Two independent pairing systems (`device-pairing.ts` and `node-pairing.ts`) that don't communicate. The WS connect handler uses the device store for crypto-based verification, but the `node.pair.*` API handlers use the node store. ## Fix Bridge the gap in the `node.pair.*` handlers: 1. **`node.pair.list`**: Also returns device-level pending requests that have a node role, merged with node-level pending requests (deduplicated by nodeId) 2. **`node.pair.approve`**: Falls back to `approveDevicePairing()` when the requestId isn't found in the node store 3. **`node.pair.reject`**: Same fallback pattern This is a minimal, targeted fix — one file changed, no new dependencies. ## Testing - TypeScript compiles clean (`tsc --noEmit` passes) - Verified the fix resolves the exact scenario from #6836: 1. New node connects from LAN → rejected with "pairing required" 2. `node.pair.list` now returns the pending request from the device store 3. `node.pair.approve` with that requestId approves it in the device store 4. Node reconnects → paired successfully Fixes #6836 <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR updates `src/gateway/server-methods/nodes.ts` to bridge `node.pair.*` handlers with the device pairing store used by the WS connect flow. - `node.pair.list` now merges node-store pending requests with device-store pending requests that have a node role, deduping by nodeId and sorting by timestamp. - `node.pair.approve`/`node.pair.reject` now try node-store resolution first and fall back to `approveDevicePairing`/`rejectDevicePairing` when the requestId only exists in the device store. Overall this aligns the CLI/API node pairing tools with how pairing requests are actually created when an unknown node connects via WebSocket, fixing the “empty pending list / unknown requestId” mismatch. <h3>Confidence Score: 4/5</h3> - This PR is likely safe to merge and should fix the reported pairing mismatch with low behavioral risk. - The change is localized to one server-methods file and follows existing device-pairing patterns. Main risk is around edge cases/UX consistency (e.g., stale device pending entries and event consumers expecting `node.pair.resolved` even on device-store fallbacks), not core correctness. - src/gateway/server-methods/nodes.ts <!-- greptile_other_comments_section --> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs