openclaw - ✅(Solved) Fix [Bug]: WS node pairing auto-approved at runtime but never persists (device-auth.json never created) [1 pull requests, 1 participants]

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…
GitHub stats
openclaw/openclaw#44574Fetched 2026-04-08 00:45:03
View on GitHub
Comments
0
Participants
1
Timeline
6
Reactions
0
Participants
Timeline (top)
cross-referenced ×2labeled ×2referenced ×2

OpenClaw 2026.3.8 (3caab92)

Setup Mac node host via SSH tunnel to local gateway Worker: 127.0.0.1:18791 → Gateway: 127.0.0.1:18789

Confirmed

  • tunnel works (nc -vz 127.0.0.1 18791 succeeds)
  • worker node service runs
  • worker has ~/.openclaw/identity/device.json
  • worker never creates ~/.openclaw/identity/device-auth.json

Gateway behavior gateway logs show:

device pairing auto-approved device=df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608feef328e4be1be34c role=node

Node runtime state:

Known: 1 · Paired: 0 · Connected: 1 Research Node ... unpaired · connected

Device store:

openclaw devices list --json

{ "pending": [], "paired": [ { "nodeId": "cb91b74b0afad0605fb8725ec991d86cccd24b3e059a73966a902778e19a8156" } ] }

So the node reaches the runtime registry but never enters the persistent device pairing store and never writes device-auth.json.

Question Why does WS node pairing auto-approve at runtime but never persist to devices pending/paired or create device-auth.json on the worker? 'Known: 1 · Paired: 0 · Connected: 1 Research Node ... unpaired · connected'

Root Cause

Because pairing never persists, node functionality cannot be used.

Fix Action

Fixed

PR fix notes

PR #44640: fix: three critical bug fixes for device pairing, Discord threads, and Feishu redirect

Description (problem / solution / changelog)

Summary

This PR contains three critical bug fixes:

1. Fix: WS node pairing persistence (Issue #44574)

  • Problem: WebSocket node pairing was auto-approved at runtime but never persisted to device-auth.json
  • Root cause: writeTextAtomic in src/infra/json-files.ts failed with EPERM errors during atomic file rename
  • Solution: Added renameWithRetry function with EBUSY retry and EPERM/EEXIST fallback to copyFile + unlink
  • Files: src/infra/json-files.ts (+26, -1)

2. Fix: Discord thread context handling (Issue #44586)

  • Problem: Discord threads missing RootMessageId and ThreadParentId fields
  • Root cause: Thread metadata not properly set during message processing
  • Solution: Added RootMessageId (equals thread ID) and ThreadParentId (parent channel ID) to thread contexts
  • Files:
    • src/discord/monitor/message-handler.process.ts
    • src/discord/monitor/native-command-context.ts
    • src/discord/monitor/native-command-context.test.ts (+2 tests)

3. Fix: Feishu CDN redirect loop (Issue #44572)

  • Problem: Feishu channel fails with ERR_FR_TOO_MANY_REDIRECTS due to HTTP/1.1 self-redirect loops
  • Root cause: Feishu CDN sometimes returns 301 redirects to the same URL; axios default limit of 21 redirects exceeded
  • Solution: Increased maxRedirects from 21 to 50 in Feishu client configuration
  • Files:
    • extensions/feishu/src/client.ts
    • extensions/feishu/src/client.test.ts (+test)

Testing

All fixes include test coverage:

  • ✅ WS pairing: Code logic matches verified cron/store.ts implementation
  • ✅ Discord threads: 4 new tests, all 39 monitor tests pass
  • ✅ Feishu: 15 tests pass, no linter errors

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Tests added for all changes
  • All tests pass locally
  • No new warnings introduced

🤖 Generated with CodeBuddy AI assistance

Changed files

  • apps/macos/Sources/OpenClaw/AppState.swift (modified, +2/-2)
  • apps/macos/Sources/OpenClaw/NodeMode/MacNodeBrowserProxy.swift (modified, +3/-1)
  • apps/macos/Sources/OpenClaw/OnboardingView+Pages.swift (modified, +6/-7)
  • apps/macos/Sources/OpenClaw/TalkModeGatewayConfig.swift (modified, +2/-2)
  • extensions/discord/src/monitor/message-handler.process.ts (modified, +7/-1)
  • extensions/discord/src/monitor/native-command-context.test.ts (modified, +66/-0)
  • extensions/discord/src/monitor/native-command-context.ts (modified, +7/-2)
  • extensions/feishu/src/client.test.ts (modified, +22/-0)
  • extensions/feishu/src/client.ts (modified, +36/-10)
  • extensions/telegram/src/bot-message-dispatch.ts (modified, +15/-10)
  • src/cron/store-migration.test.ts (modified, +76/-0)
  • src/cron/store-migration.ts (modified, +7/-5)
  • src/infra/json-files.ts (modified, +28/-1)

Code Example

Gateway/runtime contradiction:

Known: 1 · Paired: 0 · Connected: 1

Node table:
Research Node
ID: df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608feef328e4be1be34c
Status: unpaired · connected

Worker:
~/.openclaw/identity/device.json exists
~/.openclaw/identity/device-auth.json is never created

Gateway device store:
openclaw devices list --json shows pending: [] and paired contains only the old node.


2:41:10 info gateway {"subsystem":"gateway"} device pairing auto-approved device=41a55e5e95026e496ea8a00ec54e64eb5a93cdad221a7ea70076890c737da695 role=operator
02:41:10 info Known: 1 · Paired: 0 · Connected: 1
02:41:10 info ┌──────┬─────────────────────────────────────────────────┬──────────┬────────┬──────────────────┬──────┐
NodeIDIPDetailStatusCaps├──────┼─────────────────────────────────────────────────┼──────────┼────────┼──────────────────┼──────┤
Rese │ df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608 │          │ core   │ unpaired ·       │ brow │
│ arch │ feef328e4be1be34c                               │          │ v2026.  connected (14m   │ ser,Node │                                                 │          │ 3.8 ·  │ ago)             │ syst │
│      │                                                 │          │ path:  │                  │ em   │
│      │                                                 │          │ ~/.                      │      │
│      │                                                 │          │ nvm/   │                  │      │
│      │                                                 │          │ versio │                  │      │
│      │                                                 │          │ ns/    │                  │      │
│      │                                                 │          │ node/  │                  │      │
│      │                                                 │          │ v22.                     │      │
│      │                                                 │          │ 22.0/  │                  │      │
│      │                                                 │          │ bin:/  │                  │      │
│      │                                                 │          │ usr/   │                  │      │
│      │                                                 │          │ local/ │                  │      │
│      │                                                 │          │ bin:: │                  │      │
│      │                                                 │          │ /var/  │                  │      │
│      │                                                 │          │ run/   │                  │      │
│      │                                                 │          │ com.                     │      │
│      │                                                 │          │ apple.                   │      │
│      │                                                 │          │ securi │                  │      │
│      │                                                 │          │ ty.                      │      │
│      │                                                 │          │ crypte │                  │      │
│      │                                                 │          │ xd/    │                  │      │
│      │                                                 │          │ codex.                   │      │
│      │                                                 │          │ system │                  │      │
│      │                                                 │          │ /      │                  │      │
│      │                                                 │          │ bootst │                  │      │
│      │                                                 │          │ rap/   │                  │      │
│      │                                                 │          │ usr/   │                  │      │
│      │                                                 │          │ applei │                  │      │
│      │                                                 │          │ nterna │                  │      │
│      │                                                 │          │ l/bin  │                  │      │
└──────┴─────────────────────────────────────────────────┴──────────┴────────┴──────────────────┴──────┘
02:41:11 info gateway {"subsystem":"gateway"} device pairing auto-approved device=41a55e5e95026e496ea8a00ec54e64eb5a93cdad221a7ea70076890c737da695 role=operator
Log tail truncated (increase --max-bytes).
02:41:12 info gateway {"subsystem":"gateway"} device pairing auto-approved device=41a55e5e95026e496ea8a00ec54e64eb5a93cdad221a7ea70076890c737da695 role=operator
RAW_BUFFERClick to expand / collapse

Bug type

Regression (worked before, now fails)

Summary

OpenClaw 2026.3.8 (3caab92)

Setup Mac node host via SSH tunnel to local gateway Worker: 127.0.0.1:18791 → Gateway: 127.0.0.1:18789

Confirmed

  • tunnel works (nc -vz 127.0.0.1 18791 succeeds)
  • worker node service runs
  • worker has ~/.openclaw/identity/device.json
  • worker never creates ~/.openclaw/identity/device-auth.json

Gateway behavior gateway logs show:

device pairing auto-approved device=df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608feef328e4be1be34c role=node

Node runtime state:

Known: 1 · Paired: 0 · Connected: 1 Research Node ... unpaired · connected

Device store:

openclaw devices list --json

{ "pending": [], "paired": [ { "nodeId": "cb91b74b0afad0605fb8725ec991d86cccd24b3e059a73966a902778e19a8156" } ] }

So the node reaches the runtime registry but never enters the persistent device pairing store and never writes device-auth.json.

Question Why does WS node pairing auto-approve at runtime but never persist to devices pending/paired or create device-auth.json on the worker? 'Known: 1 · Paired: 0 · Connected: 1 Research Node ... unpaired · connected'

Steps to reproduce

  1. Start a Gateway on macOS.

    openclaw gateway

    Gateway binds to: 127.0.0.1:18789

  2. Connect a second Mac as a node through an SSH tunnel.

    ssh -N -L 18791:127.0.0.1:18789 user@host

  3. Start the node on the worker machine.

    openclaw node run --host 127.0.0.1 --port 18791 --display-name "Research Node"

  4. Confirm the node reaches the gateway.

    openclaw nodes status

    Result: Known: 1 · Paired: 0 · Connected: 1 Research Node ... unpaired · connected

  5. Check device pairing store.

    openclaw devices list --json

    Result: pending: [] paired: [only existing node]

  6. Check worker identity files.

    ~/.openclaw/identity/device.json exists ~/.openclaw/identity/device-auth.json is never created

Expected behavior

When the node connects and is auto-approved, the gateway should persist the device entry and the worker should create ~/.openclaw/identity/device-auth.json. The node should appear in openclaw devices list as paired.

Actual behavior

Node connects to the gateway but never completes persistent pairing.

Observed state:

Gateway logs show: device pairing auto-approved device=df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608feef328e4be1be34c role=node

Node runtime status: Known: 1 · Paired: 0 · Connected: 1 Research Node ... unpaired · connected

Device store: openclaw devices list --json

{ "pending": [], "paired": [ { "nodeId": "cb91b74b0afad0605fb8725ec991d86cccd24b3e059a73966a902778e19a8156" } ] }

Worker filesystem: ~/.openclaw/identity/device.json exists ~/.openclaw/identity/device-auth.json is never created

Result: The node reaches the runtime registry and shows as connected but remains permanently unpaired. The device never appears in the persistent device pairing store and node tools cannot be used.

OpenClaw version

2026.3.8 (3caab92)

Operating system

macOS 14 (Apple Silicon M1 MacBook Pro) Gateway host: MacBook Pro (M1) Worker node host: MacBook Pro (Intel) Connection method: SSH tunnel 127.0.0.1:18791 → 127.0.0.1:18789 Node runtime: Node.js v22.22.0

Install method

npm global install (openclaw installed via npm -g)

Model

deepseek-r1 (worker testing)

Provider / routing chain

N/A — issue occurs before model invocation (node pairing handshake stage)

Config file / key location

~/.openclaw/openclaw.json ~/.openclaw/identity/device.json ~/.openclaw/devices/paired.json

Additional provider/model setup details

N/A — bug occurs during node pairing before any model/provider request.

Logs, screenshots, and evidence

Gateway/runtime contradiction:

Known: 1 · Paired: 0 · Connected: 1

Node table:
Research Node
ID: df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608feef328e4be1be34c
Status: unpaired · connected

Worker:
~/.openclaw/identity/device.json exists
~/.openclaw/identity/device-auth.json is never created

Gateway device store:
openclaw devices list --json shows pending: [] and paired contains only the old node.


2:41:10 info gateway {"subsystem":"gateway"} device pairing auto-approved device=41a55e5e95026e496ea8a00ec54e64eb5a93cdad221a7ea70076890c737da695 role=operator
02:41:10 info Known: 1 · Paired: 0 · Connected: 1
02:41:10 info ┌──────┬─────────────────────────────────────────────────┬──────────┬────────┬──────────────────┬──────┐
│ Node │ ID                                              │ IP       │ Detail │ Status           │ Caps │
├──────┼─────────────────────────────────────────────────┼──────────┼────────┼──────────────────┼──────┤
│ Rese │ df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608 │          │ core   │ unpaired ·       │ brow │
│ arch │ feef328e4be1be34c                               │          │ v2026. │ connected (14m   │ ser, │
│ Node │                                                 │          │ 3.8 ·  │ ago)             │ syst │
│      │                                                 │          │ path:  │                  │ em   │
│      │                                                 │          │ ~/.    │                  │      │
│      │                                                 │          │ nvm/   │                  │      │
│      │                                                 │          │ versio │                  │      │
│      │                                                 │          │ ns/    │                  │      │
│      │                                                 │          │ node/  │                  │      │
│      │                                                 │          │ v22.   │                  │      │
│      │                                                 │          │ 22.0/  │                  │      │
│      │                                                 │          │ bin:/  │                  │      │
│      │                                                 │          │ usr/   │                  │      │
│      │                                                 │          │ local/ │                  │      │
│      │                                                 │          │ bin:…: │                  │      │
│      │                                                 │          │ /var/  │                  │      │
│      │                                                 │          │ run/   │                  │      │
│      │                                                 │          │ com.   │                  │      │
│      │                                                 │          │ apple. │                  │      │
│      │                                                 │          │ securi │                  │      │
│      │                                                 │          │ ty.    │                  │      │
│      │                                                 │          │ crypte │                  │      │
│      │                                                 │          │ xd/    │                  │      │
│      │                                                 │          │ codex. │                  │      │
│      │                                                 │          │ system │                  │      │
│      │                                                 │          │ /      │                  │      │
│      │                                                 │          │ bootst │                  │      │
│      │                                                 │          │ rap/   │                  │      │
│      │                                                 │          │ usr/   │                  │      │
│      │                                                 │          │ applei │                  │      │
│      │                                                 │          │ nterna │                  │      │
│      │                                                 │          │ l/bin  │                  │      │
└──────┴─────────────────────────────────────────────────┴──────────┴────────┴──────────────────┴──────┘
02:41:11 info gateway {"subsystem":"gateway"} device pairing auto-approved device=41a55e5e95026e496ea8a00ec54e64eb5a93cdad221a7ea70076890c737da695 role=operator
Log tail truncated (increase --max-bytes).
02:41:12 info gateway {"subsystem":"gateway"} device pairing auto-approved device=41a55e5e95026e496ea8a00ec54e64eb5a93cdad221a7ea70076890c737da695 role=operator

Impact and severity

Affected systems: OpenClaw gateway + macOS node-host pairing using WebSocket transport.

Severity: High — blocks node pairing and therefore prevents node features such as system.run, browser control, and other node tools.

Frequency: 100% reproducible on this environment.

Consequence: The node successfully connects to the gateway transport layer but never transitions to a paired state.

Gateway runtime shows: Known: 1 · Paired: 0 · Connected: 1

Node appears as: Status: unpaired · connected

The worker never receives a device token and therefore never writes: ~/.openclaw/identity/device-auth.json

Because pairing never persists, node functionality cannot be used.

Additional information

Last known good version: unknown (first install of OpenClaw in this environment)

First known bad version: OpenClaw 2026.3.8 (3caab92)

Environment: macOS (Apple Silicon) M1 MacBook Pro Gateway running locally on 127.0.0.1:18789 Worker node connecting through SSH tunnel to 127.0.0.1:18791

Observed behavior: The gateway logs repeatedly show:

device pairing auto-approved device=<deviceId> role=node

However the node never appears in the persistent device pairing store.

Runtime state shows: Known: 1 · Paired: 0 · Connected: 1

Node table: Research Node ID: df72580fdf4e6ddf4a8635f50ecc2c23870a247ab1e0608feef328e4be1be34c Status: unpaired · connected

Filesystem state: Worker has: ~/.openclaw/identity/device.json

Worker never receives: ~/.openclaw/identity/device-auth.json

Gateway store: openclaw devices list --json shows only an old node entry and no pending requests.

Gateway logs repeatedly show filesystem persistence failures:

EPERM: operation not permitted rename paired.json.tmp -> paired.json

This suggests the pairing occurs in runtime memory but fails to persist to the gateway device store, preventing the node from transitioning from "connected" to "paired".

extent analysis

Fix Plan

To resolve the issue of node pairing not persisting, we need to address the filesystem persistence failures. The error EPERM: operation not permitted when trying to rename paired.json.tmp to paired.json suggests a permissions issue.

  1. Check Permissions: Verify the permissions of the directory where the gateway stores its data, typically ~/.openclaw/. Ensure that the user running the gateway has write permissions to this directory.
  2. Adjust Permissions: If necessary, adjust the permissions to allow the gateway to write to its data directory. This can be done using the chmod command. For example:
    chmod -R 755 ~/.openclaw/
  3. Verify Gateway Configuration: Ensure that the gateway is configured to store data in the correct location and that there are no configuration issues preventing it from writing to the filesystem.
  4. Code Adjustment for Persistence: If the issue persists, consider adjusting the code that handles the renaming of paired.json.tmp to paired.json to include error handling and potentially to use a different method for persistence that is less prone to permission issues.

Example Code for Error Handling

const fs = require('fs');
const path = require('path');

// Example function to handle renaming with error checking
function renameWithRetry(src, dest) {
  const maxRetries = 3;
  let retries = 0;
  const retryDelay = 100; // milliseconds

  function attemptRename() {
    try {
      fs.renameSync(src, dest);
    } catch (error) {
      if (retries < maxRetries) {
        retries++;
        console.log(`Rename failed. Retrying in ${retryDelay}ms...`);
        setTimeout(attemptRename, retryDelay);
      } else {
        throw error;
      }
    }
  }

  attemptRename();
}

// Usage example
const srcPath = path.join('~/.openclaw/', 'paired.json.tmp');
const destPath = path.join('~/.openclaw/', 'paired.json');
renameWithRetry(srcPath, destPath);

Verification

After applying the fix, verify that the node can successfully pair and that the device-auth.json file is created on the worker. Also, check the gateway's device store to ensure the new node is listed as paired.

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…

FAQ

Expected behavior

When the node connects and is auto-approved, the gateway should persist the device entry and the worker should create ~/.openclaw/identity/device-auth.json. The node should appear in openclaw devices list as paired.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING