Skip to content

[Bug]: sessions_spawn fails with missing scope operator.write despite full-scope operator token #77807

@one-box-u

Description

@one-box-u

Summary

sessions_spawn fails on OpenClaw 2026.5.4 with:

missing scope: operator.write

even after the local operator device token and paired-device state have been rotated/synced to include the full operator scope set.

A direct Gateway agent RPC using the same operator device token and the same full scopes succeeds, so the failure appears specific to the sessions_spawn -> spawnSubagentDirect -> callGateway(method="agent") path.

This looks related to earlier pairing required / scope-upgrade reports for internal gateway-client self-calls, but the current observable failure is missing scope: operator.write even when the stored token scopes are already correct.

Environment

  • OpenClaw: 2026.5.4 (325df3e)
  • OS: Linux x64
  • Node: v22.22.2
  • Gateway: local Gateway, token auth enabled
  • Agent session: main agent session, sessions_spawn tool available
  • Runtime/model details do not appear relevant; failure happens before the child agent turn starts

Related issues

Possibly related, but not identical:

The difference here is that the stored operator device token already has operator.write, and a direct agent RPC succeeds with that token, while the built-in sessions_spawn tool still fails.

Steps to reproduce

  1. Run OpenClaw 2026.5.4 with a local Gateway using token auth.
  2. Ensure sessions_spawn is available in the main agent session.
  3. Confirm the paired operator device and local device-auth token include full scopes:
operator.admin
operator.approvals
operator.pairing
operator.read
operator.write
operator.talk.secrets
  1. Call sessions_spawn from the main agent session with a minimal native subagent task:
{
  "runtime": "subagent",
  "mode": "run",
  "label": "subagent-smoke-test",
  "task": "Smoke test. Reply briefly. Do not use tools.",
  "timeoutSeconds": 120,
  "runTimeoutSeconds": 120
}

Actual behavior

sessions_spawn returns an error:

{
  "status": "error",
  "error": "missing scope: operator.write",
  "childSessionKey": "<redacted>",
  "runId": "<redacted>"
}

The child session key/run id are created, but the child run does not start successfully.

Expected behavior

sessions_spawn should start the subagent run when the local operator token has operator.write, or the internal Gateway call should use an auth path/scopes that satisfy the agent RPC requirement.

Diagnostics performed

1. Verified stored operator scopes

Both the paired-device state and the local operator device-auth token contain the full scope set:

operator.admin, operator.approvals, operator.pairing, operator.read, operator.talk.secrets, operator.write

The paired token and local cached token were also verified to be identical after manual rotation/sync.

No token, device id, user id, IP, or account/channel identifier is included here.

2. openclaw devices rotate via CLI was denied

Running the documented rotate command with full scopes was denied:

GatewayClientRequestError: device token rotation denied

From source inspection, this appears to happen because the CLI method call for device.token.rotate connects with the least-privilege method scope (operator.pairing), while rotating a token that includes operator.admin / operator.write / operator.approvals requires the caller connection itself to hold those scopes.

3. Direct full-scope WS device.token.rotate succeeded

Using a direct Gateway WebSocket client with the existing operator device token and explicit full scopes, device.token.rotate succeeded and returned a new full-scope operator token.

The local device-auth cache was then synced to the newly rotated token and verified against the paired-device state.

4. sessions_spawn still failed after successful rotation/sync

After rotation and local cache sync, the same sessions_spawn smoke test still returned:

missing scope: operator.write

5. Direct Gateway agent RPC succeeds with same token/scopes

As a control test, a direct Gateway WebSocket client was created using the same operator device token and the same full scope list, then called the agent RPC directly with a minimal message and a fresh session key.

That direct agent call succeeded and returned a run id:

{
  "ok": true,
  "runId": "<redacted>"
}

This strongly suggests the Gateway agent RPC and the operator token are valid, and the failure is in the built-in sessions_spawn path rather than in Gateway auth generally.

Source-level hypothesis

From the installed build:

  • sessions_spawn calls spawnSubagentDirect(...)
  • spawnSubagentDirect(...) eventually calls callSubagentGateway({ method: "agent", ... })
  • agent is classified as requiring operator.write
  • callGateway(...) defaults to backend gateway-client behavior and least-privilege/shared-auth handling unless explicit scopes/device auth are supplied

The observed behavior is consistent with the internal callGateway(method="agent") path connecting without an effective operator.write scope, even though the local operator device token has it.

In this environment, direct WS with explicit device token + full scopes works; built-in sessions_spawn does not.

Impact

High for multi-agent workflows: native subagent delegation is blocked even though the operator token and Gateway are otherwise functional.

This prevents using subagents for task decomposition, review, and execution isolation.

Privacy note

All device IDs, session keys, run IDs, IP addresses, tokens, token hashes, user/account IDs, and channel identifiers have been redacted or omitted intentionally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    staleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions