#doctor recommends key rotate but I'm getting error.

1 messages · Page 1 of 1 (latest)

dense sail
#
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
mossy citrusBOT
#

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 operator token, 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

dense sail
#

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

mossy citrusBOT
#

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:

  1. Connect with the gateway shared secret/admin-capable auth, then run the rotate again.
  2. 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

dense sail
#

│ - 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

mossy citrusBOT
#

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.

dense sail
#

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

mossy citrusBOT
#

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.

dense sail
#

ping@bashbitch:~/workspace$ TOKEN="$(openclaw config get gateway.auth.token)"^C
ping@bashbitch:~/workspace$ echo $TOKEN
OPENCLAW_REDACTED

mossy citrusBOT
#

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 🦞

dense sail
#

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

mossy citrusBOT
#

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.

dense sail
#

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