openclaw - 💡(How to fix) Fix [Bug]: `openclaw status --json` emits `[secrets] …` diagnostic lines on stdout before the JSON document, breaking `jq` / `JSON.parse` consumers (sibling of closed `#72962`)

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…

When openclaw status --json runs against a config that has any unresolved SecretRef (and/or when the gateway is unreachable, including the protocol-mismatch case from #79099), the command emits [secrets] status --json: … diagnostic lines on stdout before the JSON document. This makes the resulting stdout invalid JSON: JSON.parse and jq both fail at byte 1. Same defect class as closed #72962 (models status --json emitting [agents/auth-profiles] log to stdout before JSON), but at a different log emit site that the #72962 fix did not cover. Reproduces on v2026.5.10-beta.1 (today's npm beta) and the same code path exists in v2026.5.7 (today's npm stable).

Error Message

$ pnpm openclaw status --json 2>/dev/null | python3 -c 'import sys,json; print(json.loads(sys.stdin.read()))' JSON.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)

Root Cause

  1. jq (or python -m json.tool, or node -e "console.log(JSON.parse(require('fs').readFileSync('/tmp/status.json','utf-8')))") fails at line 1 because stdout contains [secrets] … warning lines before {.

Fix Action

Fix / Workaround

The JSON document doesn't start until byte offset 663 on this run — 663 bytes of [secrets] and pnpm-wrapper preamble precede {. Workaround for users is to manually strip everything up to the first {:

Code Example

pnpm openclaw status --json > /tmp/status.json
   jq . /tmp/status.json

---

> openclaw@2026.5.10-beta.1 openclaw /home/orin/Gittensor/OpenCoven/openclaw-upstream
> node scripts/run-node.mjs status --json

[secrets] status --json: failed to resolve channels.discord.token locally (Environment variable "DISCORD_BOT_TOKEN" is missing or empty.).
[secrets] status --json: channels.discord.token is unavailable in this command path; continuing with degraded read-only config.
[secrets] status --json: gateway secrets.resolve unavailable (gateway closed (1002): protocol mismatch
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /home/orin/.openclaw/openclaw.json
Bind: loopback); attempted local command-secret resolution.
{
  "runtimeVersion": "2026.5.10-beta.1",
}

---

$ pnpm openclaw status --json 2>/dev/null | python3 -c 'import sys,json; print(json.loads(sys.stdin.read()))'
JSON.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)

---

$ pnpm openclaw status --json 2>/dev/null | awk '/^{/ { found=1 } found' | jq .

---

if (params.runtime) {
    for (const entry of diagnostics) {
      params.runtime.log(`[secrets] ${entry}`);
    }
  }

---
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

When openclaw status --json runs against a config that has any unresolved SecretRef (and/or when the gateway is unreachable, including the protocol-mismatch case from #79099), the command emits [secrets] status --json: … diagnostic lines on stdout before the JSON document. This makes the resulting stdout invalid JSON: JSON.parse and jq both fail at byte 1. Same defect class as closed #72962 (models status --json emitting [agents/auth-profiles] log to stdout before JSON), but at a different log emit site that the #72962 fix did not cover. Reproduces on v2026.5.10-beta.1 (today's npm beta) and the same code path exists in v2026.5.7 (today's npm stable).

Steps to reproduce

  1. On v2026.5.10-beta.1 (commit 9c7e67b0f8) — the same code path is in v2026.5.7 (src/cli/command-config-resolution.ts:30-34).

  2. Have a config that triggers a secrets-resolution fallback. The simplest trigger: a channel with a SecretRef whose env var is unset in the shell running the command. Example from this box: channels.discord.token is a SecretRef pointing at env DISCORD_BOT_TOKEN, which is not exported in the shell.

  3. Run:

    pnpm openclaw status --json > /tmp/status.json
    jq . /tmp/status.json
  4. jq (or python -m json.tool, or node -e "console.log(JSON.parse(require('fs').readFileSync('/tmp/status.json','utf-8')))") fails at line 1 because stdout contains [secrets] … warning lines before {.

Expected behavior

--json mode should produce only the JSON document on stdout. Informational/diagnostic lines should either:

  1. Be routed to stderr in --json mode (consistent with how some other commands handle it), or
  2. Be suppressed entirely when --json is set, or
  3. Be embedded inside the JSON document as a structured diagnostics: [...] field so machine consumers can still see them without breaking parseability.

This is exactly the contract that closed #72962 was filed and merged to enforce for models status --json; the same contract should hold for status --json and for any other --json command path.

Actual behavior

Verbatim stdout capture on v2026.5.10-beta.1 (commit 9c7e67b0f8), run pnpm openclaw status --json > /tmp/status.json:

> [email protected] openclaw /home/orin/Gittensor/OpenCoven/openclaw-upstream
> node scripts/run-node.mjs status --json

[secrets] status --json: failed to resolve channels.discord.token locally (Environment variable "DISCORD_BOT_TOKEN" is missing or empty.).
[secrets] status --json: channels.discord.token is unavailable in this command path; continuing with degraded read-only config.
[secrets] status --json: gateway secrets.resolve unavailable (gateway closed (1002): protocol mismatch
Gateway target: ws://127.0.0.1:18789
Source: local loopback
Config: /home/orin/.openclaw/openclaw.json
Bind: loopback); attempted local command-secret resolution.
{
  "runtimeVersion": "2026.5.10-beta.1",
}

Parseability check on the same stdout:

$ pnpm openclaw status --json 2>/dev/null | python3 -c 'import sys,json; print(json.loads(sys.stdin.read()))'
JSON.decoder.JSONDecodeError: Expecting value: line 2 column 1 (char 1)

The JSON document doesn't start until byte offset 663 on this run — 663 bytes of [secrets] and pnpm-wrapper preamble precede {. Workaround for users is to manually strip everything up to the first {:

$ pnpm openclaw status --json 2>/dev/null | awk '/^{/ { found=1 } found' | jq .

…but that's user-side defensive parsing the --json contract should make unnecessary.

Source trace on v2026.5.10-beta.1:

  • src/cli/command-config-resolution.ts:30-34:

    if (params.runtime) {
      for (const entry of diagnostics) {
        params.runtime.log(`[secrets] ${entry}`);
      }
    }

    Each diagnostic from resolveSecretsForCommand(...) (defined in src/cli/command-secret-gateway.ts) is written via runtime.log — which goes to console.log → stdout (src/runtime.ts:70-76, runtime.log impl).

  • The --json output goes through the same runtime.log path for the JSON document. So both diagnostics and JSON land on stdout, with diagnostics first because they happen during config-resolution which precedes the actual status --json payload build.

  • The commandName: "status --json" string is passed through from src/commands/status.scan.fast-json.ts:58 and ends up as a prefix inside the diagnostic message. This means the developer was aware these diagnostics are emitted from --json mode — they just don't get routed to stderr.

stderr separately contains gateway connect failed: GatewayClientRequestError: protocol mismatch (twice). Routing the [secrets] diagnostics through the same stderr path would resolve the JSON-pipe defect without losing diagnostic information for interactive operators.

OpenClaw version

v2026.5.10-beta.1

Operating system

Ubuntu 24.04

Install method

No response

Model

Not applicable

Provider / routing chain

Not applicable

Additional provider/model setup details

No response

Logs, screenshots, and evidence

Impact and severity

No response

Additional information

No response

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

--json mode should produce only the JSON document on stdout. Informational/diagnostic lines should either:

  1. Be routed to stderr in --json mode (consistent with how some other commands handle it), or
  2. Be suppressed entirely when --json is set, or
  3. Be embedded inside the JSON document as a structured diagnostics: [...] field so machine consumers can still see them without breaking parseability.

This is exactly the contract that closed #72962 was filed and merged to enforce for models status --json; the same contract should hold for status --json and for any other --json command path.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: `openclaw status --json` emits `[secrets] …` diagnostic lines on stdout before the JSON document, breaking `jq` / `JSON.parse` consumers (sibling of closed `#72962`)