ping@bashbitch:~/workspace$ openclaw devices rotate --device 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --role operator
:lobster: OpenClaw 2026.5.10-beta.2 (8287402) — Self-hosted, self-updating, self-aware (just kidding... unless?).
│
â—‡
[openclaw] Could not start the CLI.
[openclaw] Reason: device token rotation denied
[openclaw] Stack:
[openclaw] GatewayClientRequestError: device token rotation denied
[openclaw] at GatewayClient.handleMessage (file:///home/ping/.npm-global/lib/node_modules/openclaw/dist/client-Dm94UZTR.js:649:25)
[openclaw] at WebSocket.<anonymous> (file:///home/ping/.npm-global/lib/node_modules/openclaw/dist/client-Dm94UZTR.js:296:35)
[openclaw] at WebSocket.emit (node:events:519:28)
[openclaw] at Receiver.receiverOnMessage (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:1225:20)
[openclaw] at Receiver.emit (node:events:519:28)
[openclaw] at Receiver.dataMessage (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/receiver.js:596:14)
[openclaw] at Receiver.getData (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/receiver.js:496:10)
[openclaw] at Receiver.startLoop (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/receiver.js:167:16)
[openclaw] at Receiver._write (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/receiver.js:94:10)
[openclaw] at writeOrBuffer (node:internal/streams/writable:572:12)
[openclaw] Try: openclaw doctor
[openclaw] Help: openclaw --help
#doctor recommends key rotate but I'm getting error.
1 messages · Page 1 of 1 (latest)
That error is an authz denial from the gateway, not a syntax problem.
For openclaw devices rotate, the current CLI connection must be allowed to mutate that device token:
- paired-device auth can rotate only its own device unless it has
operator.admin - the target role must already exist on that device’s approved pairing contract
- if rotating an
operatortoken, the scopes can’t exceed what the current caller already has
So the usual causes are: doctor suggested rotating device 9a..., but this CLI session is authenticated as a different paired device, or it’s using a limited operator token that can’t preserve/mint the target operator scopes.
Quick checks:
openclaw devices list --json
openclaw logs --follow
Then retry the rotate and watch the gateway log — it should include a more specific reason=... like device-ownership-mismatch or a scope issue.
If devices list doesn’t show that device, you’re not connected as an admin/authorized caller for it. Use the gateway’s shared token/password/admin-capable auth, or run the rotation from the device/session that actually owns that pairing.
Docs: https://docs.openclaw.ai/cli/devices and https://docs.openclaw.ai/gateway/troubleshooting
May 10 20:30:48 bashbitch node[911988]: 2026-05-10T20:30:48.049+00:00 [gateway] device token rotation denied device=9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a role=operator reason=caller-missing-scope scope=operator.admin
May 10 20:30:48 bashbitch node[911988]: 2026-05-10T20:30:48.051+00:00 [ws] ⇄ res ✗ device.token.rotate 3ms errorCode=INVALID_REQUEST errorMessage=device token rotation denied conn=0b183cca…7342 id=659c7f75…312c
Yep, that nails it: the token you’re currently connected with does not have operator.admin, but the token you’re trying to rotate currently includes operator.admin.
OpenClaw won’t let a lower-scoped caller rotate/preserve a broader token, because that would effectively let it re-mint admin access.
Fix options:
- Connect with the gateway shared secret/admin-capable auth, then run the rotate again.
- Or rotate/request only scopes the current caller has, e.g. non-admin scopes — but only do this if you intentionally want to downgrade that device token:
openclaw devices rotate --device 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --role operator --scope operator.read --scope operator.write --scope operator.pairing
If doctor is recommending rotation for token drift, I’d prefer option 1 so you preserve the intended admin scope instead of accidentally downgrading the device. Docs: https://docs.openclaw.ai/gateway/operator-scopes
│ - Paired device cli (9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a) │
│ has no active operator device token even though the role is approved. This commonly │
│ ends in pairing-required or device-token-mismatch. Rotate a fresh token with openclaw │
This is the output from doctor, I have no other access to the gateway
Ahh, got it. If you have shell access to the machine running the gateway, that is your recovery path. You don’t need an existing paired device token — create/use a shared gateway token, then rotate from that admin-capable auth path.
Try this on bashbitch:
openclaw doctor --generate-gateway-token
openclaw gateway restart
TOKEN="$(openclaw config get gateway.auth.token)"
openclaw devices rotate \
--device 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a \
--role operator \
--token "$TOKEN"
If doctor --generate-gateway-token says a token already exists, skip that line and just read it with openclaw config get gateway.auth.token.
The important bit is --token "$TOKEN": without it, the CLI is trying to use the broken/limited paired-device path, which is why the gateway says caller-missing-scope scope=operator.admin.
Also: don’t remove the pairing yet. Rotate first; removing/re-approving is the fallback if rotation still can’t recover it.
looking at the devices list, it seems that is remains from when I wanted to have another claw node, but I ended up not needing it
Yeah — if that paired device is just stale/unused, don’t rotate it. Remove the pairing instead, and doctor should stop warning about it.
Use the shared gateway token path so you’re not blocked by the stale device’s missing/admin token:
TOKEN="$(openclaw config get gateway.auth.token)"
openclaw devices remove 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --token "$TOKEN"
openclaw doctor
If there’s no configured token yet:
openclaw doctor --generate-gateway-token
openclaw gateway restart
Then rerun the TOKEN=... + devices remove commands.
Only caveat: make sure that device id isn’t your current CLI/control UI pairing. If the display name says it was the abandoned extra node/CLI, removing it is the clean fix.
ping@bashbitch:~/workspace$ TOKEN="$(openclaw config get gateway.auth.token)"^C
ping@bashbitch:~/workspace$ echo $TOKEN
OPENCLAW_REDACTED
Yep — config get intentionally redacts secrets, so TOKEN literally became __OPENCLAW_REDACTED__. That placeholder can’t authenticate.
Since you have shell access, the cleanest recovery is to set a fresh gateway token that you know, restart, use it once, then keep it somewhere safe:
NEW_TOKEN="$(openssl rand -hex 32)"
openclaw config set gateway.auth.token "$NEW_TOKEN"
openclaw gateway restart
openclaw devices remove 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --token "$NEW_TOKEN"
openclaw doctor
Important: this rotates the gateway shared token, so any dashboard/browser/node/client using the old shared token will need the new one. But for a stale abandoned device, this is much better than trying to resurrect its operator token.
Also don’t paste the new token here — claws safe 🦞
ping@bashbitch:~/workspace$ TOKEN="$(jq .gateway.auth.token ~/.openclaw/openclaw.json)"
That populates the token
ping@bashbitch:~/workspace$ openclaw devices remove 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --token "$TOKEN"
🦞 OpenClaw 2026.5.10-beta.2 (8287402) — The lobster in your shell. 🦞
│
gateway connect failed: GatewayClientRequestError: unauthorized: gateway token mismatch (set gateway.remote.token to match gateway.auth.token)
â—‡
[openclaw] Could not start the CLI.
[openclaw] Reason: gateway closed (1008): unauthorized: gateway token mismatch (set gateway.remote.token to match gateway.auth.token)
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /home/ping/.openclaw/openclaw.json
Bind: lan
[openclaw] Stack:
[openclaw] GatewayTransportError: gateway closed (1008): unauthorized: gateway token mismatch (set gateway.remote.token to match gateway.auth.token)
[openclaw] Gateway target: ws://127.0.0.1:18789
[openclaw] Source: local loopback
[openclaw] Config: /home/ping/.openclaw/openclaw.json
[openclaw] Bind: lan
[openclaw] at createGatewayCloseTransportError (file:///home/ping/.npm-global/lib/node_modules/openclaw/dist/call-D2OMvli0.js:240:9)
[openclaw] at Object.onClose (file:///home/ping/.npm-global/lib/node_modules/openclaw/dist/call-D2OMvli0.js:324:10)
[openclaw] at WebSocket.<anonymous> (file:///home/ping/.npm-global/lib/node_modules/openclaw/dist/client-Dm94UZTR.js:333:23)
[openclaw] at WebSocket.emit (node:events:519:28)
[openclaw] at WebSocket.emitClose (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:273:10)
[openclaw] at Socket.socketOnClose (/home/ping/.npm-global/lib/node_modules/openclaw/node_modules/ws/lib/websocket.js:1346:15)
[openclaw] at Socket.emit (node:events:519:28)
[openclaw] at TCP.<anonymous> (node:net:346:12)
[openclaw] Try: openclaw doctor
[openclaw] Help: openclaw --help
Tiny shell gotcha first: jq .gateway.auth.token includes JSON quotes, so your TOKEN is probably literally "abc...", which will mismatch.
Use -r:
TOKEN="$(jq -r '.gateway.auth.token' ~/.openclaw/openclaw.json)"
openclaw devices remove 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --token "$TOKEN"
If that still says mismatch, then the running gateway is not using the token from ~/.openclaw/openclaw.json — likely OPENCLAW_GATEWAY_TOKEN in the service env, or a different config/source. Check:
openclaw gateway status
systemctl --user show openclaw-gateway --property=Environment
Then either pass the runtime env token, or set a fresh known token and restart:
NEW_TOKEN="$(openssl rand -hex 32)"
openclaw config set gateway.auth.token "$NEW_TOKEN"
openclaw gateway restart
openclaw devices remove 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --token "$NEW_TOKEN"
I’d try the jq -r fix first — that’s the most likely immediate issue.
ping@bashbitch:~/workspace$ TOKEN="$(jq -r '.gateway.auth.token' ~/.openclaw/openclaw.json)"
ping@bashbitch:~/workspace$ openclaw devices remove 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a --token "$TOKEN"
🦞 OpenClaw 2026.5.10-beta.2 (8287402) — Type the command with confidence—nature will provide the stack trace if needed.
│
â—‡
Removed 9a182680adc766e2db15daa5b59faee9452de47df29859e6d373939ce70efe7a
wicked! thanks