openclaw - 💡(How to fix) Fix CLI status/audit probe can fail with missing scope: operator.read while main Control UI auth works [3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#52071Fetched 2026-04-08 01:15:59
View on GitHub
Comments
3
Participants
3
Timeline
3
Reactions
0
Author
Timeline (top)
commented ×3

openclaw gateway status / openclaw security audit --deep can report gateway.probe_failed with missing scope: operator.read even when the main Control UI session is authenticated and working.

This appears to be a probe-path credential resolution bug in the CLI/daemon status code, not a real failure of the primary web UI auth path.

Error Message

  • gateway.error: "missing scope: operator.read"

Root Cause

openclaw gateway status / openclaw security audit --deep can report gateway.probe_failed with missing scope: operator.read even when the main Control UI session is authenticated and working.

This appears to be a probe-path credential resolution bug in the CLI/daemon status code, not a real failure of the primary web UI auth path.

Code Example

const [health, status, presence, configSnapshot] = await Promise.all([
  client.request("health"),
  client.request("status"),
  client.request("system-presence"),
  client.request("config.get", {})
]);

---

const daemonProbeAuth = await resolveGatewayProbeAuthWithSecretInputs({
  cfg: daemonCfg,
  mode: daemonCfg.gateway?.mode === "remote" ? "remote" : "local",
  env: mergedDaemonEnv,
  explicitAuth: { token: opts.rpc.token, password: opts.rpc.password }
});

---

function resolveGatewayProbeCredentialsFromConfig(params) {
  return resolveGatewayCredentialsFromConfig({
    cfg: params.cfg,
    env: params.env,
    explicitAuth: params.explicitAuth,
    modeOverride: params.mode,
    includeLegacyEnv: false,
    remoteTokenFallback: "remote-only"
  });
}

---

function resolveGatewayDriftCheckCredentialsFromConfig(params) {
  return resolveGatewayCredentialsFromConfig({
    cfg: params.cfg,
    env: {},
    modeOverride: "local",
    localTokenPrecedence: "config-first"
  });
}
RAW_BUFFERClick to expand / collapse

Summary

openclaw gateway status / openclaw security audit --deep can report gateway.probe_failed with missing scope: operator.read even when the main Control UI session is authenticated and working.

This appears to be a probe-path credential resolution bug in the CLI/daemon status code, not a real failure of the primary web UI auth path.

Environment

  • OpenClaw version: 2026.3.13
  • Install method: pnpm / npm-installed package
  • OS: macOS 26.3.1
  • Gateway mode: local
  • Gateway auth mode: token
  • gateway.auth.token: configured
  • gateway.remote: unset / none
  • Main web UI client: openclaw-control-ui

Actual behavior

  • openclaw security audit --deep reports:
    • gateway.probe_failed
    • missing scope: operator.read
  • openclaw status --json reports:
    • gateway.reachable: false
    • gateway.error: "missing scope: operator.read"
  • Meanwhile the main web UI session is healthy and can successfully call operator-read methods.

Expected behavior

For a local token-auth gateway with gateway.auth.token configured, the CLI status/audit probe should authenticate with the same effective local read credential and should not fail with missing scope: operator.read.

What makes this look like a probe-path bug

Gateway logs show two distinct behaviors:

  1. A healthy webchat session for openclaw-control-ui connects and successfully calls methods including:

    • status
    • cron.status
    • cron.list
    • models.list
    • channels.status
    • config.schema
    • sessions.list
  2. Separate short-lived connections repeatedly call exactly:

    • status
    • system-presence
    • config.get

    and fail with:

    • missing scope: operator.read

Those failing calls recur on a timer and look like an internal probe client, not the main UI session.

Code-path evidence

1) The failing RPC trio matches daemon-cli.js probe code

In dist/daemon-cli.js, probeGateway() creates a GatewayClient in PROBE mode and, on connect, calls:

const [health, status, presence, configSnapshot] = await Promise.all([
  client.request("health"),
  client.request("status"),
  client.request("system-presence"),
  client.request("config.get", {})
]);

That exactly matches the recurring failing log pattern.

2) status builds probe auth through a specialized probe resolver

runDaemonStatus() / status gather path calls:

const daemonProbeAuth = await resolveGatewayProbeAuthWithSecretInputs({
  cfg: daemonCfg,
  mode: daemonCfg.gateway?.mode === "remote" ? "remote" : "local",
  env: mergedDaemonEnv,
  explicitAuth: { token: opts.rpc.token, password: opts.rpc.password }
});

3) The probe resolver uses a different policy than the working local drift-check resolver

Probe resolver:

function resolveGatewayProbeCredentialsFromConfig(params) {
  return resolveGatewayCredentialsFromConfig({
    cfg: params.cfg,
    env: params.env,
    explicitAuth: params.explicitAuth,
    modeOverride: params.mode,
    includeLegacyEnv: false,
    remoteTokenFallback: "remote-only"
  });
}

Drift-check resolver:

function resolveGatewayDriftCheckCredentialsFromConfig(params) {
  return resolveGatewayCredentialsFromConfig({
    cfg: params.cfg,
    env: {},
    modeOverride: "local",
    localTokenPrecedence: "config-first"
  });
}

Why this looks wrong for local token-auth setups

In the affected config:

  • gateway.mode = local
  • gateway.auth.mode = token
  • gateway.auth.token is present
  • gateway.remote is not configured
  • no OPENCLAW_GATEWAY_TOKEN env is set in the invoking shell

So the safe credential source for the local probe is clearly gateway.auth.token.

But the probe path uses a specialized resolver policy that differs from the working local drift-check path:

  • it does not force localTokenPrecedence: "config-first"
  • it does carry remoteTokenFallback: "remote-only"

That looks like the likely reason the probe path fails while the main UI and local dashboard still work.

Minimal repro shape

  1. Configure a local gateway with:
    • gateway.mode = local
    • gateway.auth.mode = token
    • gateway.auth.token set
    • no gateway.remote.token
  2. Start gateway normally.
  3. Confirm main Control UI works.
  4. Run:
    • openclaw status --json
    • openclaw security audit --deep
  5. Observe probe failure with missing scope: operator.read despite healthy main UI auth.

Suggested fix direction

For local probe/status/audit paths, align credential resolution with the local drift-check behavior:

  • force local mode for local gateway probes
  • prefer gateway.auth.token with localTokenPrecedence: "config-first"
  • avoid remoteTokenFallback: "remote-only" when probing a local gateway

At minimum, the probe credential policy should match the effective auth source used by the healthy local UI/client path.

Notes

This issue persisted even after:

  • verifying the main UI session had working operator access
  • confirming the dashboard-side token injection was fixed
  • adjusting paired device scope metadata

Those changes did not clear the CLI/audit probe warning, which further suggests the bug is specific to the internal probe credential resolver.

extent analysis

Fix Plan

To resolve the issue, we need to align the credential resolution for local probe/status/audit paths with the local drift-check behavior.

Here are the steps:

  • Update the resolveGatewayProbeAuthWithSecretInputs function to force local mode for local gateway probes.
  • Prefer gateway.auth.token with localTokenPrecedence: "config-first" for local probes.
  • Avoid remoteTokenFallback: "remote-only" when probing a local gateway.

Example code changes:

function resolveGatewayProbeCredentialsFromConfig(params) {
  return resolveGatewayCredentialsFromConfig({
    cfg: params.cfg,
    env: params.env,
    explicitAuth: params.explicitAuth,
    modeOverride: "local", // Force local mode for local gateway probes
    includeLegacyEnv: false,
    localTokenPrecedence: "config-first", // Prefer gateway.auth.token
    remoteTokenFallback: null // Avoid remote-only fallback for local probes
  });
}

Verification

To verify the fix, follow these steps:

  • Configure a local gateway with gateway.mode = local, gateway.auth.mode = token, and gateway.auth.token set.
  • Start the gateway normally.
  • Confirm the main Control UI works.
  • Run openclaw status --json and openclaw security audit --deep.
  • Verify that the probe failure with missing scope: operator.read is resolved.

Extra Tips

  • Ensure that the gateway.auth.token is correctly set and valid.
  • Verify that the local drift-check resolver is working correctly.
  • Test the fix with different configurations and scenarios to ensure it is robust and reliable.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

For a local token-auth gateway with gateway.auth.token configured, the CLI status/audit probe should authenticate with the same effective local read credential and should not fail with missing scope: operator.read.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING