#gateway pairing error
1 messages · Page 1 of 1 (latest)
That gateway closed (1008): pairing required means the client device you’re connecting from (CLI or browser Control UI) isn’t paired/approved with the Gateway yet.
1) First: don’t start a 2nd gateway
You already have one running on 127.0.0.1:18789 (Port 18789 is already in use).
So use e.g. openclaw gateway status / openclaw gateway restart rather than starting another instance.
2) Approve the device pairing request
On the gateway host (same machine where the gateway process is running), run:
openclaw devices list
openclaw devices approve <requestId>
Then retry whatever was failing (Control UI refresh, or openclaw status, etc.).
Docs: https://docs.openclaw.ai/web/control-ui (Device pairing section)
Devices CLI: https://docs.openclaw.ai/cli/devices
3) Sanity check: are you connecting from another device?
Your status output says “Loopback-only gateway; only local clients can connect.”
So if you’re trying to connect from your phone/another computer, you’ll need remote access (Tailscale Serve or an SSH tunnel) first — otherwise only the local machine can reach it.
If you tell me what command you ran (and whether you’re trying from the same Mac vs another device/browser), I can point you to the exact minimal fix.
Hi the openclaw devices list command gave error
root@ubuntu-s-2vcpu-4gb-120gb-intel-nyc3-01:~# openclaw devices list
🦞 OpenClaw 2026.2.19-2 (45d9b20) — Your messages, your servers, your control.
│
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
Config: /root/.openclaw/openclaw.json
Bind: loopback
at Object.onClose (file:///usr/lib/node_modules/openclaw/dist/call-DZzTR0NL.js:438:10)
at WebSocket.<anonymous> (file:///usr/lib/node_modules/openclaw/dist/client-DoSZFvf3.js:1538:23)
at WebSocket.emit (node:events:519:28)
at WebSocket.emitClose (/usr/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:273:10)
at Socket.socketOnClose (/usr/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)
Yep — this is the annoying part: openclaw devices list is itself an operator call, so if the Gateway thinks your CLI is a non-local device, it will refuse the WS handshake with “pairing required”, and you can’t even list the pending requests.
Normally true loopback clients are auto-approved (“silent” pairing). So when it isn’t auto-approving, it almost always means the Gateway is not seeing your connection as loopback, even though you’re dialing ws://127.0.0.1:18789.
Most common cause: Gateway is in Docker / behind a local proxy
If port 18789 is published via docker-proxy (or you’re hitting nginx/caddy), the Gateway will see your source IP as something like 172.17.0.1 (not 127.0.0.1) → not local → pairing required.
Check what’s actually listening on 18789:
ss -lntp | grep 18789
- If you see docker-proxy: run the pairing commands inside the container, where
127.0.0.1is really loopback to the Gateway:
docker compose setup (docs path):
docker compose run --rm openclaw-cli devices list
docker compose run --rm openclaw-cli devices approve <requestId>
(or docker exec -it <gateway-container> openclaw devices list)
Docs: https://docs.openclaw.ai/install/docker#control-ui-token--pairing-docker
If it’s not Docker
Paste these outputs and I’ll tell you exactly what it’s seeing as the “remoteIp”:
openclaw gateway status
openclaw logs --follow
When you re-run openclaw devices list, the gateway log usually prints a device pairing requestId (the CLI currently doesn’t always show it), and we can work from there.
root@ubuntu-s-2vcpu-4gb-120gb-intel-nyc3-01:~# openclaw gateway status
🦞 OpenClaw 2026.2.19-2 (45d9b20) — Because texting yourself reminders is so 2024.
│
gateway connect failed: Error: pairing required
â—‡
Service: systemd (enabled)
File logs: /tmp/openclaw/openclaw-2026-02-20.log
Command: /usr/bin/node /usr/lib/node_modules/openclaw/dist/index.js gateway --port 18789
Service file: ~/.config/systemd/user/openclaw-gateway.service
Service env: OPENCLAW_GATEWAY_PORT=18789
Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json
Gateway: bind=loopback (127.0.0.1), port=18789 (service args)
Probe target: ws://127.0.0.1:18789
Dashboard: http://127.0.0.1:18789/
Probe note: Loopback-only gateway; only local clients can connect.
Runtime: running (pid 13055, state active, sub running, last exit 0, reason 0)
Warm-up: launch agents can take a few seconds. Try again shortly.
RPC probe: failed
RPC target: ws://127.0.0.1:18789
gateway closed (1008): pairing required
Gateway target: ws://127.0.0.1:18789
Source: cli --url
Config: /root/.openclaw/openclaw.json
Port 18789 is already in use.
- pid 13055 root: openclaw-gateway (127.0.0.1:18789)
- Gateway already running locally. Stop it (openclaw gateway stop) or use a different port.
Listening: 127.0.0.1:18789
Troubles: run openclaw status
Troubleshooting: https://docs.openclaw.ai/troubleshooting
root@ubuntu-s-2vcpu-4gb-120gb-intel-nyc3-01:~# openclaw logs --follow
🦞 OpenClaw 2026.2.19-2 (45d9b20) — End-to-end encrypted, drama-to-drama excluded.
gateway connect failed: Error: pairing required
Gateway not reachable. Is it running and accessible?
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /root/.openclaw/openclaw.json
Bind: loopback
Hint: run openclaw doctor.
Short answer: the Gateway is treating your CLI connection as non‑local, so it creates a device pairing request with silent=false and closes the WS (1008: pairing required). That usually means the gateway saw either proxy headers from an untrusted proxy or a non‑local Host header — common when a reverse proxy / docker-proxy / Tailscale Serve is in front of the gateway, or the client is in a different network namespace.
What I need from you (fast diagnostics) — please run these on the gateway host and paste ONLY the lines I ask for (do not paste gateway tokens or secrets into the public channel).
- Look for the gateway warnings that explain why it refused to auto‑approve:
-
journalctl (user service):
journalctl --user -u openclaw-gateway --no-pager -n 400 | grep -Ei 'proxy|loopback|pairing|device.pair|device identity' || true -
logfile (alternate):
tail -n 300 /tmp/openclaw/openclaw-*.log | grep -Ei 'Proxy headers|Loopback connection|pairing required|device.pair' || true
If you see either:
- "Proxy headers detected from untrusted address" → the gateway saw X-Forwarded-* but the remote connection (the proxy) is NOT in gateway.trustedProxies.
- "Loopback connection with non-local Host header" → the TCP endpoint is loopback but the Host header in the request was NOT localhost/127.0.0.1 (so the gateway treats it as remote).
Copy the matching log lines here (redact any tokens). Those lines tell us which of the two cases you have.
- Dump the device pairing store (no gateway RPC required — we read the files directly):
- cat ~/.openclaw/devices/pending.json 2>/dev/null || echo "no pending file"
- cat ~/.openclaw/devices/paired.json 2>/dev/null || echo "no paired file"
If there is a pending request, paste only the requestId, deviceId, remoteIp and silent fields (or paste the whole pending.json but redact token values). That lets me tell you the next command to approve.
Quick/secure workarounds (choose one)
A) Fast & safe: generate a gateway token and use it to authenticate the CLI (this lets the CLI skip device identity and approve the pending device)
- Generate and write a token (runs doctor and will update config):
openclaw doctor --generate-gateway-token --yes - Show the token (do NOT paste it into public channels; keep it secret):
openclaw config get gateway.auth.token - Restart the gateway so it picks up the new config:
systemctl --user restart openclaw-gateway
(or: openclaw gateway restart)
- Use the token to list & approve:
openclaw devices list --token "<TOKEN>" --url ws://127.0.0.1:18789
openclaw devices approve <requestId> --token "<TOKEN>" --url ws://127.0.0.1:18789
B) If logs show "Proxy headers detected from untrusted address"
- Add your proxy IP(s) to gateway.trustedProxies (example for docker-proxy/host bridge 172.17.0.1):
openclaw config set gateway.trustedProxies '["172.17.0.1"]'
systemctl --user restart openclaw-gateway - Re-run openclaw gateway status — local clients should now be recognized as local and auto‑approved.
C) If logs show "Loopback connection with non-local Host header"
- Make sure you call the gateway with a local Host header. Easiest: force the CLI to use the loopback URL explicitly and do not route it through any HTTP proxy:
openclaw devices list --url ws://127.0.0.1:18789 - If a reverse proxy is rewriting Host, make it forward proper X‑Forwarded headers and add the proxy IP to gateway.trustedProxies (see B).
If you’re on Docker/docker‑compose (or the gateway is containerized), run the CLI inside the gateway container/network namespace (so the gateway sees the client as local):
- docker exec -it <gateway-container> openclaw devices list
or
- docker compose run --rm openclaw-cli openclaw devices list
If you can't or don't want to generate a token, paste the two things I asked for above (the relevant gateway log lines and the pending.json entry). Tell me whether this VPS is running any reverse proxy (nginx, caddy, traefik), Tailscale Serve, or Docker port publishing — that lets me give the minimal config change to fix trustedProxies/Host issues.
Safety note: do NOT paste gateway tokens or password values here. Pastes of requestId, remoteIp, and the specific log warnings are fine.
If you want, paste the log lines now and I’ll tell you the exact config change/command to run next.
Feb 20 06:02:12 <host> node[pid]: 2026-02-20T06:02:12.741Z [ws] closed before connect conn=<conn_1> remote=<loopback> fwd=n/a origin=n/a host=<loopback>:<port> ua=n/a code=1008 reason=pairing required
Feb 20 06:02:57 <host> node[pid]: 2026-02-20T06:02:57.907Z [gateway] security audit: device access upgrade requested reason=scope-upgrade device=<device_id> ip=unknown-ip auth=token roleFrom=operator roleTo=operator scopesFrom=operator.read scopesTo=operator.admin,operator.approvals,operator.pairing client=cli conn=<conn_2>
Feb 20 06:02:57 <host> node[pid]: 2026-02-20T06:02:57.998Z [ws] closed before connect conn=<conn_2> remote=<loopback> fwd=n/a origin=n/a host=<loopback>:<port> ua=n/a code=1008 reason=pairing required
Feb 20 17:24:46 <host> node[pid]: 2026-02-20T17:24:46.915Z [ws] closed before connect conn=<conn_3> remote=<loopback> fwd=n/a origin=n/a host=<loopback>:<port> ua=n/a code=1008 reason=pairing required
@open cobalt
Those log lines are super helpful: you’re not failing auth — you’re failing device pairing on a scope upgrade:
reason=scope-upgrade … scopesFrom=operator.read → scopesTo=operator.admin,operator.approvals,operator.pairing- then the WS is closed:
code=1008 reason=pairing required
Normally, loopback connections auto-approve that pairing request. So the key question is: why is the Gateway deciding your connection is not “local direct”?
Most likely cause (and it fits your redaction)
isLocalDirectRequest() only considers the request “local” if both are true:
- client IP resolves to loopback (
127.*/::1) âś… - Host header is exactly
localhostor127.0.0.1or::1(or ends with.ts.net) ✅/❌
If you’re connecting via a hostname that resolves to loopback (very common on Ubuntu via 127.0.1.1 <hostname>), then:
- remote is loopback âś…
- BUT host header is
<hostname>❌ → treated as remote → pairing not silent → you get the deadlock you’re seeing.
Quick test / fix
Force the CLI to connect with a local Host header (localhost), and pass the token explicitly (because --url disables implicit creds):
TOKEN="$(openclaw config get gateway.auth.token)"
openclaw devices list \
--url ws://localhost:18789 \
--token "$TOKEN"
If that starts working, the next run of openclaw gateway status should also stop failing (because the scope-upgrade pairing will get auto-approved on local).
If you still get pairing required, try the other allowed host:
openclaw devices list --url ws://127.0.0.1:18789 --token "$TOKEN"
One thing I need you to paste (not secret)
In your log lines, the host=... field is the smoking gun, but you redacted it to <loopback>:<port>. Can you paste one of those lines with the real host=... value intact?
Example of what to paste (just the host= bit is enough):
host=localhost:18789host=127.0.0.1:18789host=your-vps-hostname:18789host=127.0.1.1:18789
That will confirm whether this is the “hostname-on-loopback” edge case.
If it turns out host is not local-ish
Then the fix is simply: make sure your Gateway URL / any proxy/tunnel uses localhost or 127.0.0.1 for local CLI calls (not the machine hostname), or we adjust your setup so the Host header is local.
Run the two commands above and tell me:
- which one (if any) succeeds
- the real
host=...from the log line
im getting the gateway 1006 error now
1006 is “abnormal closure” — i.e. the WebSocket connection died before the gateway could send a close frame. That’s usually not a “pairing required” situation; it’s more like: gateway crashed/restarted, wrong scheme (ws vs wss), or something (proxy/firewall) is cutting the connection mid-handshake.
To narrow it down, can you paste the exact command + the exact error block you see (the part that includes “Gateway target/Source/Config”, but redact tokens)?
Meanwhile, on the VPS run these and paste output (again, redact secrets):
- Confirm the gateway is actually listening and hasn’t died:
ss -lntp | grep 18789 || true
- Check for gateway crashes/errors around the time you got 1006:
tail -n 200 /tmp/openclaw/openclaw-*.log
(or if you’re using systemd user service logs)
journalctl --user -u openclaw-gateway --no-pager -n 200
- Check whether you’re supposed to use
ws://orwss://:
openclaw config get gateway.tls.enabled
- if
true→ usewss://… - if
false→ usews://…
Also: tell me if you’re connecting directly to 127.0.0.1/localhost (good) or through any reverse proxy / Cloudflare / nginx / Docker port publishing / Tailscale Serve (common cause of 1006 if WS upgrade isn’t forwarded).
openclaw@ubuntu-s-2vcpu-4gb-120gb-intel-nyc3-01:~$ openclaw gateway status
🦞 OpenClaw 2026.2.19-2 (45d9b20) — Automation with claws: minimal fuss, maximal pinch.
│
â—‡
Service: systemd (disabled)
File logs: /tmp/openclaw-1000/openclaw-2026-02-20.log
Service config looks out of date or non-standard.
Service config issue: Gateway service PATH is not set; the daemon should use a minimal PATH.
Recommendation: run "openclaw doctor" (or "openclaw doctor --repair").
Config (cli): ~/.openclaw/openclaw.json
Config (service): ~/.openclaw/openclaw.json
Gateway: bind=loopback (127.0.0.1), port=18789 (env/config)
Probe target: ws://127.0.0.1:18789
Dashboard: http://127.0.0.1:18789/
Probe note: Loopback-only gateway; only local clients can connect.
Runtime: unknown (Error: systemctl --user unavailable: Failed to connect to bus: No medium found)
RPC probe: failed
RPC target: ws://127.0.0.1:18789
gateway closed (1006 abnormal closure (no close frame)): no close reason
Gateway target: ws://127.0.0.1:18789
Source: cli --url
Config: /home/openclaw/.openclaw/openclaw.json
systemd user services unavailable.
systemd user services are unavailable; install/enable systemd or run the gateway under your supervisor.
If you're in a container, run the gateway in the foreground instead of openclaw gateway.
this is my gateway status right now
That status output explains the shift:
- systemctl --user is not usable in your current environment (
Failed to connect to bus: No medium found) - the RPC probe is hitting ws://127.0.0.1:18789 and getting 1006 (connection drops without a WS close frame)
1006 almost always means you’re not actually talking to a healthy OpenClaw gateway WS endpoint (gateway not running, crashed, or something else/proxy is on that port and closes the upgrade).
1) First: is anything listening on 18789?
Run and paste output:
ss -lntp | grep 18789 || true
2) If something is listening: is it really OpenClaw?
Quick HTTP check (safe to paste headers/output):
curl -sv http://127.0.0.1:18789/ 2>&1 | head -80
If you get an HTML page (Control UI) or OpenClaw-ish headers → good.
If you get “connection refused” / some other server banner → that explains 1006.
3) Check the gateway log for a crash/stacktrace
Your log path is:
/tmp/openclaw-1000/openclaw-2026-02-20.log
Run:
tail -n 200 /tmp/openclaw-1000/openclaw-2026-02-20.log
4) About the “systemctl --user unavailable” part (important)
This happens in two common cases:
A) You’re in a container / no systemd as PID 1
Check:
ps -p 1 -o comm=
- If that’s not
systemd, you won’t havesystemctl --user. In that case, run the gateway in the foreground (or under tmux/supervisor):
openclaw gateway --port 18789 --bind loopback
B) You are on a real VPS with systemd, but user services aren’t started (no user bus)
Then you can fix it by enabling lingering for the openclaw user (run as root once):
loginctl enable-linger openclaw
Log out/in (or reboot), then:
sudo -iu openclaw systemctl --user start openclaw-gateway
sudo -iu openclaw systemctl --user status openclaw-gateway
Paste results from (1) + (3) first. That’ll tell us immediately whether 18789 is empty, the gateway is crashing, or something else is on that port causing the 1006.
i did option B, and got root@ubuntu-s-2vcpu-4gb-120gb-intel-nyc3-01:~# sudo -iu openclaw systemctl --user start openclaw-gateway
Failed to connect to bus: No medium found
@open cobalt
Failed to connect to bus: No medium found means you don’t have a systemd “user session” bus for that user right now (so systemctl --user … cannot work). loginctl enable-linger alone doesn’t fix it if the user manager/bus never comes up.
First, figure out which environment you’re in:
0) Are you actually running under systemd (PID 1)?
Run (as root):
ps -p 1 -o comm=
- If it’s not
systemd(common in containers):systemctl --userwill never work → skip to Option A (foreground run).
1) Is anything listening on 18789 right now?
ss -lnt | grep 18789 || true
If nothing is listening, your 1006 is simply “gateway not running”.
Option A (recommended right now): run the gateway in the foreground
This bypasses systemd entirely and gets you unstuck immediately:
sudo -iu openclaw
openclaw gateway run --port 18789 --bind loopback
(Use tmux/screen if you want it to keep running after you disconnect.)
Then in another shell you can do the pairing/approval steps again.
Option B: make systemd user services work (if PID 1 is systemd)
On many VPSes, systemctl --user only works in a real login session for that user.
Try this sequence as root:
id -u openclaw
loginctl enable-linger openclaw
systemctl start user@$(id -u openclaw).service
ls -ld /run/user/$(id -u openclaw) || true
Then SSH in as the openclaw user directly (not sudo -iu), and run:
systemctl --user status
systemctl --user start openclaw-gateway
If that still shows “No medium found”, the box is missing the user-session D-Bus bits; on Ubuntu the package is usually:
sudo apt-get update
sudo apt-get install -y dbus-user-session
(Only do that if you’re comfortable changing the server.)
Paste back:
- output of
ps -p 1 -o comm=