Issue: sessions_spawn fails with "pairing required" on local loopback with token auth
Environment
- OpenClaw version: 2026.4.8 (upgraded from 2026.4.2)
- OS: Windows 10 (10.0.26200, x64)
- Node: v24.14.1
- Gateway config:
bind: loopback, auth.mode: token
- Channel: Feishu (direct chat)
Description
When calling sessions_spawn with runtime: "subagent" from an agent session, the spawned subagent fails to connect back to the gateway WebSocket with error:
gateway closed (1008): pairing required
Gateway target: ws://127.0.0.1:18789
Source: local loopback
This occurs despite:
- Gateway running on loopback only (
bind: loopback)
- Token auth configured (
gateway.auth.mode: "token")
- The subagent inherits the gateway token from
openclaw.json
- Agent session is fully operational (can use all other tools, exec, web_search, etc.)
Root Cause Analysis
I traced through the source code and found the issue:
Connection Flow
The subagent connects via WebSocket with:
client.id: cli (from GATEWAY_CLIENT_IDS.CLI)
client.mode: cli (from GATEWAY_CLIENT_MODES.CLI)
role: "operator" (from call-BjnDacVz.js:425)
Auth Check Path
-
evaluateMissingDeviceIdentity() in server.impl-WjqjRArz.js (~line 27570):
roleCanSkipDeviceIdentity("operator", sharedAuthOk) should return { kind: "allow" } when sharedAuthOk === true
-
shouldSkipLocalBackendSelfPairing() (~line 27641):
- Requires
client.mode === "backend", but subagent connects with mode: "cli"
- This path is never taken for subagent connections
-
roleCanSkipDeviceIdentity() (~line 10387):
- Returns
true when role === "operator" && sharedAuthOk
- This should work, but the subagent still gets rejected
Key Observation
The devices/ directory (~/.openclaw/credentials/devices/) is empty — no paired devices exist. The subagent generates a new device identity each time (resolveDeviceIdentityForGatewayCall() → loadOrCreateDeviceIdentity()), which has no matching paired device record.
It appears that sharedAuthOk may not be resolving to true for the subagent's connection, or the device identity check is happening before the shared auth check.
Relevant Code Locations
call-BjnDacVz.js:420-425 — subagent connects as mode: CLI, role: "operator"
server.impl-WjqjRArz.js:27433 — sharedAuthOk resolution
server.impl-WjqjRArz.js:27560-27575 — evaluateMissingDeviceIdentity()
server.impl-WjqjRArz.js:27641-27649 — shouldSkipLocalBackendSelfPairing()
server.impl-WjqjRArz.js:10387-10388 — roleCanSkipDeviceIdentity()
server.impl-WjqjRArz.js:28282 — final close(1008, "pairing required")
Expected Behavior
Subagent spawned by sessions_spawn on a local loopback gateway with token auth should be able to connect without requiring device pairing, since:
- The connection is local (loopback)
- Token auth is valid
- The role is "operator"
Workaround
Using exec to call claude --print --permission-mode bypassPermissions directly works fine for coding tasks, completely bypassing the subagent WebSocket connection.
Reproduction
- Set up OpenClaw on Windows with
gateway.bind: loopback, gateway.auth.mode: token
- Have a Feishu channel configured and working
- From agent session, call
sessions_spawn with runtime: "subagent" and any task
- Observe:
"gateway closed (1008): pairing required"
Suggested Fix
Either:
- Ensure
sharedAuthOk resolves correctly for subagent connections on local loopback with token auth
- Or add a skip path for locally-spawned subagents similar to
shouldSkipLocalBackendSelfPairing but for CLI-mode connections
- Or allow
roleCanSkipDeviceIdentity to work regardless of device identity when auth is valid on loopback
Issue: sessions_spawn fails with "pairing required" on local loopback with token auth
Environment
bind: loopback,auth.mode: tokenDescription
When calling
sessions_spawnwithruntime: "subagent"from an agent session, the spawned subagent fails to connect back to the gateway WebSocket with error:This occurs despite:
bind: loopback)gateway.auth.mode: "token")openclaw.jsonRoot Cause Analysis
I traced through the source code and found the issue:
Connection Flow
The subagent connects via WebSocket with:
client.id:cli(fromGATEWAY_CLIENT_IDS.CLI)client.mode:cli(fromGATEWAY_CLIENT_MODES.CLI)role:"operator"(fromcall-BjnDacVz.js:425)Auth Check Path
evaluateMissingDeviceIdentity()inserver.impl-WjqjRArz.js(~line 27570):roleCanSkipDeviceIdentity("operator", sharedAuthOk)should return{ kind: "allow" }whensharedAuthOk === trueshouldSkipLocalBackendSelfPairing()(~line 27641):client.mode === "backend", but subagent connects withmode: "cli"roleCanSkipDeviceIdentity()(~line 10387):truewhenrole === "operator" && sharedAuthOkKey Observation
The
devices/directory (~/.openclaw/credentials/devices/) is empty — no paired devices exist. The subagent generates a new device identity each time (resolveDeviceIdentityForGatewayCall()→loadOrCreateDeviceIdentity()), which has no matching paired device record.It appears that
sharedAuthOkmay not be resolving totruefor the subagent's connection, or the device identity check is happening before the shared auth check.Relevant Code Locations
call-BjnDacVz.js:420-425— subagent connects asmode: CLI, role: "operator"server.impl-WjqjRArz.js:27433—sharedAuthOkresolutionserver.impl-WjqjRArz.js:27560-27575—evaluateMissingDeviceIdentity()server.impl-WjqjRArz.js:27641-27649—shouldSkipLocalBackendSelfPairing()server.impl-WjqjRArz.js:10387-10388—roleCanSkipDeviceIdentity()server.impl-WjqjRArz.js:28282— finalclose(1008, "pairing required")Expected Behavior
Subagent spawned by
sessions_spawnon a local loopback gateway with token auth should be able to connect without requiring device pairing, since:Workaround
Using
execto callclaude --print --permission-mode bypassPermissionsdirectly works fine for coding tasks, completely bypassing the subagent WebSocket connection.Reproduction
gateway.bind: loopback,gateway.auth.mode: tokensessions_spawnwithruntime: "subagent"and any task"gateway closed (1008): pairing required"Suggested Fix
Either:
sharedAuthOkresolves correctly for subagent connections on local loopback with token authshouldSkipLocalBackendSelfPairingbut for CLI-mode connectionsroleCanSkipDeviceIdentityto work regardless of device identity when auth is valid on loopback