#How to spawn subagents
1 messages · Page 1 of 1 (latest)
If you just want to use sub-agents, you don’t need any special command — just tell your agent:
- “Spawn a sub-agent to research X”
- “Spawn a sub-agent to analyze Y. Use gpt-5.2 and set a 5-minute timeout.”
OpenClaw will call the sessions_spawn tool behind the scenes; the sub-agent runs in the background and then announces the result back into this chat when it’s done.
To manage them from the chat, use the slash commands:
/subagents list/subagents log <id|#> [limit] [tools]/subagents stop <id|#|all>/subagents send <id|#> <message>
Docs (full details + config like default subagent model / maxConcurrent):
https://docs.openclaw.ai/tools/subagents
ok, how to fix error
Gateway Error — the config token does not match the service token.
@cobalt mountain
That error means the Gateway background service is running with a different auth token than what your current config says.
In practice it happens when you changed gateway.auth.token (or OPENCLAW_GATEWAY_TOKEN) but the installed service (systemd/launchd) is still using the old token / old service metadata.
Fix (safe default)
On the machine that runs the Gateway service:
- Check what’s running / what config it’s using:
openclaw --version
openclaw gateway status
openclaw config get gateway.auth.token
- Reinstall service metadata (this usually resolves “config vs service” mismatches), then restart:
I’m here — what are you stuck on now?
If it’s still the “config token does not match the service token” issue, paste the output of:
openclaw gateway status
(and tell me macOS vs Linux).
openclaw gateway install --force
openclaw gateway restart
If you’re using token auth and want to be explicit, you can also reinstall with the token you intend to use:
openclaw gateway install --force --token "<your gateway.auth.token>"
openclaw gateway restart
(Do not paste the token into Discord.)
If you’re on macOS (common gotcha)
If you ever set a launchctl override, it can “win” over your config. Check/unset it:
launchctl getenv OPENCLAW_GATEWAY_TOKEN
launchctl unsetenv OPENCLAW_GATEWAY_TOKEN
Then openclaw gateway restart again.
If it still errors
Paste the output of openclaw gateway status (it should redact secrets) and say whether you’re on macOS or Linux.
Docs that cover this flow:
how to fix error OpenClaw ("pairing required") when bot trying to spawn other agents
@cobalt mountain
pairing required means the Gateway is refusing the request until you approve the sender/device. It’s not a “subagent spawning” error by itself — spawning just triggers some action that needs an approved device/sender.
1) If you see this in the Control UI / Dashboard
Typical message: disconnected (1008): pairing required.
Fix (approve the browser/device):
openclaw devices list
openclaw devices approve <requestId>
Notes:
127.0.0.1connections are auto-approved.- New browser profile / cleared site data = new device id = you must approve again.
Docs: https://docs.openclaw.ai/web/control-ui
2) If this happens for Discord DMs (DM policy = pairing)
Approve the DM pairing code:
openclaw pairing list discord
openclaw pairing approve discord <CODE>
Docs: https://docs.openclaw.ai/channels/pairing and https://docs.openclaw.ai/channels/discord
3) If the bot is trying to use a node (system.run/canvas/camera/screen) and fails
Nodes also require device pairing:
openclaw devices list
openclaw devices approve <requestId>
openclaw nodes status
Docs: https://docs.openclaw.ai/nodes/index
If you paste where you see pairing required (Control UI vs Discord DM vs node tool output) + the exact line, I can point you to the exact approval flow.
domalex — that ping doesn’t include details, but pairing required always means “this sender/device hasn’t been approved yet” (it’s an auth gate, not a subagent/spawn permission).
Most common fixes:
A) It’s your browser / Control UI (WS disconnect 1008)
Approve the device:
openclaw devices list
openclaw devices approve <requestId>
Docs: https://docs.openclaw.ai/web/control-ui
B) It’s Discord DM pairing
Approve the DM code:
openclaw pairing list discord
openclaw pairing approve discord <CODE>
Docs: https://docs.openclaw.ai/channels/pairing
C) It’s a node host trying to connect (often confused with “subagents”)
Node connections also require device approval:
openclaw devices list
openclaw devices approve <requestId>
openclaw nodes status
Docs: https://docs.openclaw.ai/nodes/index
If you paste the exact line where you see pairing required (Control UI? gateway logs? node logs?) + openclaw --version, I can tell you which of A/B/C applies.
OpenClaw Gateway is running but sessions_spawn fails with "pairing required" error.
Environment:
macOS 15.1.1 (arm64)
OpenClaw 2026.2.19-2
Node 22.21.1
Error:
gateway closed (1008): pairing required
Gateway target: ws://127.0.0.1:18789
Steps taken:
openclaw gateway restart — Gateway runs, RPC probe: ok
openclaw pairing list — command hangs/exits with signal 9
openclaw pairing approve — no pairing codes to approve
Cleared session locks: rm -rf ~/.openclaw/agents//sessions/.lock
Reinstalled Gateway: openclaw gateway install --force
Current state:
Gateway: running (pid varies)
RPC probe: ok
sessions_spawn: fails with "pairing required"
CLI pairing commands: unresponsive or fail
Expected: sessions_spawn should work without manual pairing (as per docs for local loopback).
Question: How to complete pairing or bypass it for local agent-to-agent spawn?
That specific error (gateway closed (1008): pairing required) is Gateway WebSocket device pairing (operator/device identity), not “subagent spawning permission” and not openclaw pairing … (that one is DM pairing codes).
So the fix path is:
1) Approve the pending device (operator) pairing
Run this on the machine that’s running the Gateway:
openclaw devices list --json --timeout 5000
If you see a pending request, approve it:
openclaw devices approve <requestId>
Docs: https://docs.openclaw.ai/web/control-ui (device pairing) and https://docs.openclaw.ai/cli/devices
2) If devices list doesn’t show anything / still fails
Then we need to figure out why the Gateway thinks the client is “non-local” (because loopback should auto-approve).
Do these checks:
openclaw config get gateway.trustedProxies
openclaw logs --follow
Then reproduce the sessions_spawn failure and look in the logs for the pairing line (it usually includes the connecting device id / role / client ip). That tells us which client is getting blocked (CLI vs Control UI vs some other worker) and what IP the Gateway is using for its “local auto-approve” check.
3) About “bypassing pairing”
There isn’t a supported “bypass pairing for sessions_spawn” knob—sessions_spawn doesn’t require pairing; your client can’t even stay connected to the Gateway WS right now, so the spawn call never gets through. Once the device pairing is approved (or the “why are you not local?” issue is fixed), spawning works normally.
If you paste:
- the output of
openclaw devices list --json(redact any tokens if present), and - the single relevant log line around “pairing required”
…I can tell you exactly what’s being blocked.
Gateway service check failed: Error: systemctl --user unavailable: Failed to connect to bus: No such file or directory
I get this error
That error just means: OpenClaw tried to query the “Gateway service” via systemctl --user, but your environment doesn’t have a working systemd user bus (so the service check can’t run). It’s common in:
- WSL2 (systemd not enabled)
- Docker / containers (no systemd)
- SSH/non-login contexts where the user manager isn’t running
- Running the check under
sudo(don’t usesudo systemctl --user …)
Quick workaround (still lets you use OpenClaw)
Run the gateway in the foreground:
openclaw gateway
# or: openclaw gateway run
To check if the gateway is actually up (without service manager):
openclaw gateway health --url ws://127.0.0.1:18789
If you’re on WSL2 (most common)
You need systemd enabled (docs): https://docs.openclaw.ai/platforms/windows
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
[boot]
systemd=true
EOF
Then in PowerShell:
wsl --shutdown
Re-open WSL and verify:
systemctl --user status
If you’re on Linux with systemd, but user bus isn’t running
Try enabling lingering (keeps the user systemd instance alive):
sudo loginctl enable-linger $USER
Then log out/in (or reboot), and re-test:
systemctl --user status
If you tell me your environment (WSL? Docker? “real” Linux?) + openclaw --version, I can point you to the right “daemon install” path.
WSL
Yep — in WSL that error almost always means systemd isn’t enabled, so systemctl --user … can’t connect to the user bus.
Fix (enable systemd in WSL2)
In your WSL distro (Ubuntu, etc.):
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
[boot]
systemd=true
EOF
Then from PowerShell (Windows side):
wsl --shutdown
Re-open your WSL terminal and verify:
ps -p 1 -o comm=
systemctl --user status
ps …should showsystemdsystemctl --user statusshould no longer error
Now you can use the gateway service flow again, e.g.:
openclaw gateway install
systemctl --user enable --now openclaw-gateway.service
openclaw gateway status
If you’re on WSL1 (or old WSL)
Systemd won’t work properly. Check:
wsl -l -v
If it shows version 1, convert to WSL2.
If you paste the output of wsl -l -v and your distro name (Ubuntu/Debian/etc.), I’ll give you the exact commands.
/root/.zshrc:4: parse error near `fi'
Nelson# ps -p 1 -o comm=
systemctl --user status
systemd
Failed to connect to bus: No such file or directory
That combo usually means you’ve got systemd as PID 1, but you don’t have a user D‑Bus session, so systemctl --user … has nothing to talk to.
Two common causes in WSL:
1) You’re running as root (your log shows /root/.zshrc…)
systemctl --user expects a per-user runtime dir like /run/user/<uid>/bus. For root in WSL that often isn’t created.
Check:
whoami
id -u
echo $XDG_RUNTIME_DIR
ls -ld /run/user/$(id -u) /run/user/$(id -u)/bus
If whoami is root: exit and re-open WSL as your normal user (or sudo -iu <youruser>). Then try:
systemctl --user status
2) Missing dbus-user-session (common in minimal distros)
Install it, then restart WSL:
sudo apt update
sudo apt install -y dbus-user-session
Then from PowerShell:
wsl --shutdown
Re-open WSL and run:
systemctl --user status
About /root/.zshrc: parse error near fi
That’s separate (a broken if … fi in root’s zshrc). It’s another hint you’re landing in a root shell. Switching to a normal user usually avoids that too.
If you paste the outputs of the 5-line “check” block above (whoami/id/XDG_RUNTIME_DIR/ls), I can tell you exactly which of the two is biting you.
thanks -
Though I got an issue now on vscode Failed to connect to the remote extension host server (Error: WebSocket close with status code 1006)
That VS Code error is from Remote‑WSL itself (not OpenClaw): the VS Code “server/extension host” in WSL drops the connection, so the client sees WebSocket close 1006.
The two most common causes match what you saw earlier:
1) Your shell startup is erroring (your …/.zshrc: parse error near 'fi')
If your default shell is zsh, a broken ~/.zshrc can crash the remote server bootstrap.
Fix options:
- Fast test: switch to bash in WSL and try again
chsh -s /bin/bash
then restart WSL (see step 2 below) and reconnect from VS Code.
- Or actually fix the broken
~/.zshrc(there’s anifmissing a matchingthen/fior similar).
2) Corrupted VS Code Server install in WSL
Resetting it is usually safe (it will re-download on next connect):
- Close VS Code.
- In PowerShell:
wsl --shutdown
- Open WSL and run:
rm -rf ~/.vscode-server ~/.vscode-server-insiders
- Re-open VS Code and “Reopen Folder in WSL”.
Quick check: are you accidentally running as root?
VS Code Remote works best as a normal Linux user.
whoami
If it says root, switch to your normal user and reconnect.
If this still fails: in VS Code open View → Output → “Remote - WSL” and paste the last ~30 lines here—those logs usually point straight at the exact rc file / missing dependency / permission issue.
System Node 12.22.9 at /usr/bin/node is below the required Node 22+. Using /home/nelson/.nvm/versions/node/v24.13.0/bin/node for the daemon. Install Node 22+ from nodejs.org or Homebrew.
That message is basically a warning about your “system” Node:
/usr/bin/node= 12.22.9 (too old)- but OpenClaw found a good Node via nvm (
~/.nvm/.../node v24.13.0) and says it will use that for the daemon.
So: if OpenClaw is indeed using the nvm Node for the service, you’re fine.
Recommended fix (WSL): make your default Node 22+ and reinstall service
In WSL as your normal user (not root):
node -v
which node
If that still shows Node 12, set a modern default in nvm:
nvm install 22
nvm alias default 22
nvm use 22
node -v
Then reinstall OpenClaw under that Node and reinstall the service:
npm i -g openclaw@latest
openclaw gateway install --force
If you want to eliminate Node 12 entirely (optional)
That old /usr/bin/node usually came from the Ubuntu/Debian nodejs package. You can upgrade via NodeSource or remove it, but I’d only do that if you’re comfortable changing system packages.
Quick sanity check: what Node is the service actually using?
Once systemctl --user works, check the unit:
systemctl --user cat openclaw-gateway.service
If you paste the ExecStart= line, I can tell you whether it’s guaranteed to run with the nvm Node or if it might still be picking up /usr/bin/node in some cases.
.nvm/versions/node/v24.13.0/bin/node"
Good — ~/.nvm/versions/node/v24.13.0/bin/node is a perfectly fine Node (22+ required, 24 is OK). The warning you saw was just because your system Node at /usr/bin/node is still 12.
To make things stable (especially for the systemd user service + VS Code Remote), do this in WSL as your normal user:
# make sure your interactive shell uses the right node
which node
node -v
# set a default node for nvm (pick one)
nvm alias default 24.13.0
nvm use default
Then reinstall the gateway service so it captures the right runtime:
openclaw gateway install --force
If systemctl --user is working for you now, confirm what the service will run:
systemctl --user cat openclaw-gateway.service
Paste the ExecStart= line here — that will tell us whether it’s pinned to the nvm node path or still depends on PATH (which could fall back to /usr/bin/node).
If VS Code Remote is still flaky: also fix that .zshrc parse error (or temporarily switch default shell to bash), because a broken shell rc can break the remote extension host bootstrap.
Thanks, that worked
Nice.
If this fixed it, please right-click the solution message → Apps → ✅ Mark Solution so Answer Overflow indexes it for the next person.
I jumped into someones chat. I had the same issue, not sure they solved theirs yet
If you want to help them quickly, paste a short “here’s what fixed it for me” in their thread. Two common “same symptoms” cases:
If they see gateway closed (1008): pairing required when spawning
That’s device pairing (Gateway WS), not DM pairing codes:
openclaw devices list
openclaw devices approve <requestId>
openclaw pairing … is for DM pairing codes and won’t fix this.
Docs: https://docs.openclaw.ai/web/control-ui (Device pairing section)
If they’re on WSL and get systemctl --user unavailable / Failed to connect to bus
Enable systemd (WSL2):
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
[boot]
systemd=true
EOF
Then in PowerShell:
wsl --shutdown
And make sure they’re not running as root, and ideally install:
sudo apt install -y dbus-user-session
If they get “System Node 12 is below required Node 22+”
Set an nvm default Node 22+ and reinstall the gateway service:
nvm install 22
nvm alias default 22
openclaw gateway install --force
If you link me the exact error line they posted, I can tell you which of these applies.
Why does wsl return to root when I Enable systemd (WSL2):
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
[boot]
systemd=true
EOF
Is there a permanent fix to avoid this?
Enabling systemd in WSL2 doesn’t inherently switch your default login to root — if you’re landing in a root shell after that, it’s almost always one of these:
1) Your distro’s default user isn’t set (so it falls back to root)
Permanent fix: set the default user in /etc/wsl.conf.
In WSL (even if you’re currently root), edit /etc/wsl.conf to include:
[boot]
systemd=true
[user]
default=nelson
Then from PowerShell:
wsl --shutdown
Re-open WSL and you should land as nelson.
2) Your Windows Terminal / VS Code profile is explicitly launching WSL as root
Check your profile commandline. If it looks like any of these, it will always open root:
wsl.exe -u root …wsl.exe -d <DistroName> -u root …
Fix: remove -u root, or set it to your user.
3) You’re actually still in a root shell because of sudo -i / sudo su
sudo tee … only runs that one command as root. It won’t flip your user.
If your prompt is root because you ran sudo -i, just exit back to your normal user.
If you paste:
wsl -l -v(PowerShell), and- the first line of your Windows Terminal profile command (or tell me if you’re opening via VS Code)
…I can point to the exact cause in your setup.
root@Nelson:~# [boot]
systemd=true
[user]
default=nelson
[boot]: command not found
[user]: command not found
root@Nelson:~# su - nelson
/home/nelson
❯ [boot]
systemd=true
[user]
default=nelson
zsh: no matches found: [boot]
[WARN] - (starship::context): Scanning current directory timed out.
[WARN] - (starship::context): You can set scan_timeout in your config to a higher value to allow longer-running scans to keep executing.
/home/nelson
❯ [boot]
systemd=true
[user]
default=nelson
zsh: no matches found: [boot]
/home/nelson
❯
You’re literally running the text as shell commands right now. Lines like [boot] are INI file sections for /etc/wsl.conf — they are not commands, so bash/zsh will error ([boot]: command not found / zsh: no matches found: [boot]).
Do this instead (this writes the file):
sudo tee /etc/wsl.conf >/dev/null <<'EOF'
[boot]
systemd=true
[user]
default=nelson
EOF
cat /etc/wsl.conf
Then restart WSL from PowerShell:
wsl --shutdown
Re-open WSL and verify:
whoami
If it still opens as root after that
Then your Windows Terminal / VS Code profile is probably launching WSL with -u root.
Check your launch command and remove the root flag (examples that force root):
wsl.exe -u root …wsl.exe -d <DistroName> -u root …
If you paste your Windows Terminal “command line” for that profile (or tell me if you only open via VS Code), I’ll tell you exactly where to change it.
Config path not found: gateway.trustedProxies
That one is expected: openclaw config get <path> errors if the key isn’t set in your config. It doesn’t mean the key is invalid/missing from OpenClaw.
To see what is set, do:
openclaw config get gateway
If you are running the Gateway behind a reverse proxy (nginx/Caddy/Tailscale Serve proxy/etc.) and you want forwarded client IPs to be trusted for “local client” checks, you can set it explicitly, e.g. same-host proxy:
openclaw config set gateway.trustedProxies '["127.0.0.1"]' --json
openclaw gateway restart
Only set this if you’re actually proxying the Gateway; otherwise you can ignore it. Docs: https://docs.openclaw.ai/gateway/security (reverse proxy + gateway.trustedProxies)
how to fix that error when bot trying to spawn agents
│ Gateway │ local · ws://127.0.0.1:18789 (local loopback) · unreachable (connect failed: pairing required) │
│ Gateway service │ LaunchAgent installed · loaded · running (pid 52429) │
That line:
unreachable (connect failed: pairing required)(even though it’sws://127.0.0.1:18789)
means the Gateway is rejecting the operator WebSocket client (your CLI / some worker) because its device identity isn’t approved yet. This is device pairing, not DM pairing.
Fix: approve the pending device
Run on the same machine/user that runs the LaunchAgent:
openclaw devices list --json
openclaw devices approve <requestId>
After approval, retry your spawn / openclaw gateway status.
Docs: https://docs.openclaw.ai/web/control-ui#device-pairing-first-connection and https://docs.openclaw.ai/cli/devices
gateway connect failed: Error: pairing required
[openclaw] Failed to start CLI: Error: gateway closed (1008): pairing required
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Bind: loopback
at Object.onClose (file:///opt/homebrew/lib/node_modules/openclaw/dist/call-DZzTR0NL.js:438:10)
at WebSocket.<anonymous> (file:///opt/homebrew/lib/node_modules/openclaw/dist/client-DoSZFvf3.js:1538:23)
at WebSocket.emit (node:events:519:28)
at WebSocket.emitClose (/opt/homebrew/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:273:10)
at Socket.socketOnClose (/opt/homebrew/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:1346:15)
at Socket.emit (node:events:519:28)
at TCP.<anonymous> (node:net:346:12)
If openclaw devices list also fails with the same “pairing required”
Then the Gateway does not consider this connection “local” (most common causes):
-
You’re running the CLI from WSL/Docker/VM (so
127.0.0.1is not actually the gateway host).
→ Run the CLI directly on the gateway host, or point--urlat the real host IP/tailnet address. -
You’re going through a reverse proxy that adds
X-Forwarded-For/X-Real-IP, and the Gateway won’t treat it as local unless proxy trust is configured.
→ Connect directly to the Gateway (bypass proxy), or configuregateway.trustedProxies(only if you actually proxy).
If you paste:
- what OS you’re on (macOS/WSL/Docker/etc), and
- whether
openclaw devices list --jsonworks or errors
…I’ll tell you which branch you’re in and the exact next step.
macOS
This is the output of openclaw devices list --json
gateway connect failed: Error: pairing required
[openclaw] Failed to start CLI: Error: gateway closed (1008): pairing required
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Bind: loopback
at Object.onClose (file:///opt/homebrew/lib/node_modules/openclaw/dist/call-DZzTR0NL.js:438:10)
at WebSocket.<anonymous> (file:///opt/homebrew/lib/node_modules/openclaw/dist/client-DoSZFvf3.js:1538:23)
at WebSocket.emit (node:events:519:28)
at WebSocket.emitClose (/opt/homebrew/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:273:10)
at Socket.socketOnClose (/opt/homebrew/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:1346:15)
at Socket.emit (node:events:519:28)
at TCP.<anonymous> (node:net:346:12)
That error is device pairing for operator clients (CLI / Control UI). It’s not a “subagents permission” issue.
On true localhost (ws://127.0.0.1:18789) this usually only happens if either:
- you’re not actually connecting directly (reverse proxy / port-forward in the middle), or
- that particular device identity got into a “needs approval” state and now the Gateway won’t auto-approve it.
Fastest fix: approve the device from the Control UI
- Open the dashboard in a browser on the same Mac:
http://127.0.0.1:18789/- (or run
openclaw dashboard --no-opento print the URL)
-
Connect with your Gateway token (don’t paste it here).
-
In the Control UI, go to the Devices / Pairing area and approve the pending operator device request.
After that, openclaw gateway status and spawning should work.
If the Control UI itself can’t connect (also says pairing required)
Temporarily allow token-only auth for the UI (break-glass), restart, approve, then turn it back off:
openclaw config set gateway.controlUi.allowInsecureAuth true --json
openclaw gateway restart
# approve device in the UI
openclaw config unset gateway.controlUi.allowInsecureAuth
openclaw gateway restart
If you’re using a reverse proxy in front of the Gateway
Then you must set trusted proxies, otherwise the gateway will refuse to treat it as “local”:
openclaw config set gateway.trustedProxies '["127.0.0.1"]' --json
openclaw gateway restart
If you tell me whether you have nginx/Caddy/Tailscale Serve/etc. in front of port 18789, I can tell you which branch you’re in.
its on local
You’re hitting device pairing, and the important clue is:
Source: local loopbackbut stillpairing required
In the Gateway code, local clients are supposed to be silent/auto‑approved. If you’re seeing “pairing required”, the Gateway has decided your connection is not local.
On macOS that almost always happens when the Gateway thinks there are reverse‑proxy headers involved (e.g. X-Forwarded-For / X-Real-IP) coming from an address that is not in gateway.trustedProxies. In that case it intentionally disables “local trust” (so you don’t accidentally bypass auth via a proxy).
Fix (most common): trust localhost as a proxy
Even if config get says “path not found”, you can still set it:
openclaw config set gateway.trustedProxies '["127.0.0.1"]' --json
openclaw gateway restart
Then retry:
openclaw devices list --json
If the local classification was the issue, this should stop the 1008 pairing close.
Docs context: https://docs.openclaw.ai/gateway/security#reverse-proxy-configuration
Quick sanity check: are you really connecting to the Gateway on 18789?
Run:
sudo lsof -nP -iTCP:18789 -sTCP:LISTEN
- If it’s not the OpenClaw gateway process (node/openclaw), you’re connecting to some proxy/other service on that port.
If it still fails after setting trustedProxies
Paste:
- output of the
lsofcommand above, and - the last ~30 lines of
~/.openclaw/logs/gateway.err.log(redact secrets)
…and we can pinpoint what is making it “non-local”.
127.0.0.1:18789 (LISTEN)
[::1]:18789 (LISTEN)
Even if the Gateway is “local”, it will still refuse to treat the connection as local (and therefore won’t auto-approve pairing) if it thinks you’re coming through a proxy.
In the gateway code there are two telltale cases that make 127.0.0.1 not count as local:
- Proxy headers present (
X-Forwarded-For/X-Real-IP) from an address that is not ingateway.trustedProxies - Loopback connection but Host header is not local (e.g. you connect through a local reverse proxy / custom hostname)
Step 1: check the real reason in the gateway log (macOS LaunchAgent)
Run:
tail -n 200 ~/.openclaw/logs/gateway.err.log
Look for either of these warnings:
Proxy headers detected from untrusted address... Configure gateway.trustedProxies...Loopback connection with non-local Host header. Treating it as remote...
Step 2: if you see proxy header warning → set trustedProxies
Most common fix on macOS (local proxy runs on localhost):
openclaw config set gateway.trustedProxies '["127.0.0.1","::1"]' --json
openclaw gateway restart
Then retry openclaw devices list --json.
Step 3 (break-glass if you’re totally stuck): use Control UI to approve the pending device
If no operator client can connect to approve pairing, temporarily allow the Control UI to connect without device identity, approve the pending device, then revert:
openclaw config set gateway.controlUi.allowInsecureAuth true --json
openclaw gateway restart
Open http://127.0.0.1:18789/, connect with your token, go to Devices/Pairing, approve the pending request(s).
Then revert:
openclaw config unset gateway.controlUi.allowInsecureAuth
openclaw gateway restart
If you paste the 5–10 log lines around the warning from gateway.err.log, I can tell you exactly which branch you’re in.
Those LISTEN lines confirm the Gateway really is on loopback — so the only remaining explanation for “pairing required” is: the gateway has a non‑silent pending device pairing request for your CLI device (often created when it previously thought the client was remote/proxied). Once such a pending request exists, local auto-approve won’t override it.
Since you can’t connect with the CLI to approve it, do a quick “reset pairing state” on disk:
1) Find the state dir the LaunchAgent is using
Usually ~/.openclaw (or ~/.openclaw-<profile>):
ls -d ~/.openclaw* 2>/dev/null
ls ~/.openclaw*/devices/pending.json 2>/dev/null
ls ~/.openclaw*/logs/gateway.err.log 2>/dev/null
2) Stop gateway, back up the pending pairing file, restart
(doesn’t delete your whole config; just clears pending device requests)
openclaw gateway stop
mv ~/.openclaw/devices/pending.json ~/.openclaw/devices/pending.json.bak.$(date +%s) 2>/dev/null || true
openclaw gateway start # or: openclaw gateway restart
3) Retry
openclaw devices list --json
If it still says pairing required
Then your CLI device identity might be “stuck”; reset it:
mv ~/.openclaw/identity/device.json ~/.openclaw/identity/device.json.bak.$(date +%s) 2>/dev/null || true
mv ~/.openclaw/identity/device-auth.json ~/.openclaw/identity/device-auth.json.bak.$(date +%s) 2>/dev/null || true
openclaw gateway restart
If you paste the last ~20 lines of ~/.openclaw/logs/gateway.err.log after a failed connect, I can tell you exactly which of the two (stale pending vs identity mismatch) it is.
The sessions_spawn Problem:
When I run sessions_spawn, it creates a sub-agent as a node and tries to connect to the Gateway via WebSocket. The Gateway requires pairing (manual approval) for all node connections.
The Deadlock:
sessions_spawn → creates sub-agent with new deviceId → tries to connect to Gateway
Gateway → rejects with "pairing required" (code 1008)
To approve pairing → need to call nodes pending or devices approve
But these commands themselves require Gateway connection → which requires pairing
Why settings don't work:
auth.mode: none — only works for webchat, not for nodes
insecureLocal: true, allowUnpaired — ignored for node role
Gateway always requires pairing for connections with role: node / clientMode: backend
Why openclaw agent --local works:
Runs agent embedded, without connecting to Gateway
No pairing required, but not integrated with your chat
The Core Issue: sessions_spawn doesn't work without approved pairing, but pairing cannot be approved without access to Gateway API.
Any ideas how to bypass this? 🌍