openclaw - ✅(Solved) Fix Status-command hint output inconsistently split between stdout and stderr [1 pull requests, 1 comments, 2 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#83925Fetched 2026-05-20 03:46:32
View on GitHub
Comments
1
Participants
2
Timeline
12
Reactions
1
Timeline (top)
labeled ×5mentioned ×2subscribed ×2commented ×1

Error Message

defaultRuntime.error(errorText("Service unit not found.")); defaultRuntime.error(errorText(hint)); defaultRuntime.error(errorText("Service is loaded but not running.")); defaultRuntime.error(errorText(hint)); When the service is not loaded at all, hints go to stdout via defaultRuntime.log. When the service is loaded but the unit is missing or it is stopped, hints go to stderr via defaultRuntime.error. Users or scripts capturing openclaw node status stdout will see hints in one case but not the other. The --json path is not taken in these branches, so JSON consumers are unaffected, but plain-text consumers (shell scripts, wrappers) will behave inconsistently depending on which failure mode they hit. Route all user-visible hints in runNodeDaemonStatus through defaultRuntime.log (stdout). Reserve defaultRuntime.error for the terse machine-readable status line ("Service unit not found.", "Service is loaded but not running.") and use defaultRuntime.log for the follow-up hint lines, matching the !loaded branch convention. Change defaultRuntime.error(errorText(hint)) to defaultRuntime.log(...) for hint lines in the missingUnit and stopped branches of runNodeDaemonStatus in src/cli/node-cli/daemon.ts.

Fix Action

Fix / Workaround

Severity: low / Confidence: high / Category: bug Triage: confirmed-bug Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18) Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-264278dce9-_9f9418d0b7.

PR fix notes

PR #84100: fix(cli): route node status hints through stdout consistently (#83925)

Description (problem / solution / changelog)

Fixes #83925.

runNodeDaemonStatus (src/cli/node-cli/daemon.ts:199-235) routed service-start hints to stdout in the !loaded branch (matching renderNodeServiceStartHints and the rest of the status pretty-printer), but the two follow-up paths — runtime.missingUnit and runtime.status === "stopped" — sent buildNodeRuntimeHints lines to stderr instead. Users running openclaw node status 2>/dev/null (or any wrapper script that captures stdout for parsing) saw hints in the "never installed" path but lost them in the "installed but unit missing / stopped" paths.

Changes

  • src/cli/node-cli/daemon.ts: keep the terse machine-readable status sentence ("Service unit not found." / "Service is loaded but not running.") on defaultRuntime.error so wrappers that already grep stderr for those exact lines continue to work, but route the follow-up buildNodeRuntimeHints loop bodies through defaultRuntime.log + infoText — matching the !loaded branch convention.

Diff stat: 1 file, +8 / -2.

Real behavior proof

  • Behavior or issue addressed: Sanitized issue evidence — when the service has never been installed, hints reach stdout via defaultRuntime.log. When the service is loaded but the unit is missing or it is stopped, the same class of hint goes to stderr via defaultRuntime.error. The --json path is unaffected (returns earlier); the inconsistency only impacts plain-text consumers.

  • Real environment tested: Local Node 22.x. Probe at /tmp/probe_83925.mjs (a) parses the patched daemon.ts and verifies the two terse status sentences still go to stderr, both hint loops now use defaultRuntime.log + infoText, and there are no remaining .error(errorText(hint)) loop bodies in the function; and (b) replays the three branches (not_loaded / missing_unit / stopped) under both the patched shape (hints on stdout in all three) and the pre-fix shape (hints on stderr in missing_unit + stopped — the asymmetry the issue reports).

  • Exact steps or command run after this patch: node /tmp/probe_83925.mjs

  • Evidence after fix:

PASS: 'Service unit not found.' status line still on stderr (machine-readable)
PASS: 'Service is loaded but not running.' status line still on stderr
PASS: both hint loops (missingUnit + stopped) route through defaultRuntime.log + infoText
PASS: no remaining .error(errorText(hint)) loop bodies (no stderr-routed hints)
PASS: replay (patched): hint lines appear on stdout in all three failure paths — consistent for `node status 2>/dev/null` consumers
PASS: replay (buggy): hints only on stderr for missing_unit/stopped — confirms the inconsistency from #83925
PASS: replay (patched): terse status sentences stay on stderr (machine consumers preserved)

ALL CASES PASS
  • Observed result after fix: openclaw node status 2>/dev/null now prints the runtime hints across all three failure modes consistently. Machine-readable consumers that already filter stderr for the terse status sentence ("Service unit not found.", "Service is loaded but not running.") are unaffected — those lines stay where they were.

  • What was not tested: Live openclaw node status against a real launchd/systemd/schtasks installation in each of the three failure modes — that requires platform-specific service setup. The probe replays the three branches end-to-end and verifies the source-level routing matches the existing !loaded branch's pattern.

Audit (per CLAUDE rules — all 5 steps)

  • Existing-helper check: Reuses the existing defaultRuntime.log, defaultRuntime.error, buildNodeRuntimeHints, errorText, and infoText helpers — all of which are already in scope. No new helper. The new routing matches the !loaded branch that already uses defaultRuntime.log + infoText for renderNodeServiceStartHints(). PASS
  • Shared-helper caller check: runNodeDaemonStatus has one production caller (src/cli/node-cli/register.ts:73). The signature is unchanged; the behavior change is presentation-only (which stream the hint lines land on). PASS
  • Broader-fix rival scan: gh pr list --search '83925 in:title,body' returns no open PRs. PASS
  • Recent-merge audit: git log --oneline -5 -- src/cli/node-cli/daemon.ts shows e1061a8b46 test(live): tolerate provider drift in release checks — unrelated. PASS
  • Prototype-pollution scan: N/A — display routing only.

Changed files

  • src/cli/node-cli/daemon.ts (modified, +8/-2)

Code Example

if (!loaded) {
    defaultRuntime.log("");
    for (const hint of renderNodeServiceStartHints()) {
      defaultRuntime.log(`${warnText("Start with:")} ${infoText(hint)}`);
    }
    return;
  }

---

if (runtime?.missingUnit) {
    defaultRuntime.error(errorText("Service unit not found."));
    for (const hint of buildNodeRuntimeHints(hintEnv)) {
      defaultRuntime.error(errorText(hint));
    }
    return;
  }

  if (runtime?.status === "stopped") {
    defaultRuntime.error(errorText("Service is loaded but not running."));
    for (const hint of buildNodeRuntimeHints(hintEnv)) {
      defaultRuntime.error(errorText(hint));
    }
  }
RAW_BUFFERClick to expand / collapse

Severity: low / Confidence: high / Category: bug Triage: confirmed-bug Detected against: openclaw v2026.5.18 (latest stable at time of scan, 2026-05-18) Tooling: clawpatch 0.3.0 + acpx/claude-sonnet-4-5 via Brad Mills protocol

Evidence

  • src/cli/node-cli/daemon.ts:199-207 (runNodeDaemonStatus)
if (!loaded) {
    defaultRuntime.log("");
    for (const hint of renderNodeServiceStartHints()) {
      defaultRuntime.log(`${warnText("Start with:")} ${infoText(hint)}`);
    }
    return;
  }
  • src/cli/node-cli/daemon.ts:218-235 (runNodeDaemonStatus)
if (runtime?.missingUnit) {
    defaultRuntime.error(errorText("Service unit not found."));
    for (const hint of buildNodeRuntimeHints(hintEnv)) {
      defaultRuntime.error(errorText(hint));
    }
    return;
  }

  if (runtime?.status === "stopped") {
    defaultRuntime.error(errorText("Service is loaded but not running."));
    for (const hint of buildNodeRuntimeHints(hintEnv)) {
      defaultRuntime.error(errorText(hint));
    }
  }

Reasoning

When the service is not loaded at all, hints go to stdout via defaultRuntime.log. When the service is loaded but the unit is missing or it is stopped, hints go to stderr via defaultRuntime.error. Users or scripts capturing openclaw node status stdout will see hints in one case but not the other. The --json path is not taken in these branches, so JSON consumers are unaffected, but plain-text consumers (shell scripts, wrappers) will behave inconsistently depending on which failure mode they hit.

Reproduction

Compare openclaw node status 2>/dev/null when the service has never been installed (hints appear) vs when the service is installed but stopped (hints disappear from stdout).

Recommendation

Route all user-visible hints in runNodeDaemonStatus through defaultRuntime.log (stdout). Reserve defaultRuntime.error for the terse machine-readable status line ("Service unit not found.", "Service is loaded but not running.") and use defaultRuntime.log for the follow-up hint lines, matching the !loaded branch convention.

Why existing tests miss this

No tests exist for this feature.

Suggested regression test

In a unit test for runNodeDaemonStatus, stub service.isLoaded to return true, service.readRuntime to return { status: 'stopped' }, capture both stdout and stderr, and assert that the hint lines appear on stdout rather than stderr.

Minimum fix scope

Change defaultRuntime.error(errorText(hint)) to defaultRuntime.log(...) for hint lines in the missingUnit and stopped branches of runNodeDaemonStatus in src/cli/node-cli/daemon.ts.


Standardized clawpatch finding. Persistent in v2026.5.18 (not resolved by upgrading from v2026.5.12). Finding ID: fnd_sig-feat-cli-command-264278dce9-_9f9418d0b7.

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…

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 - ✅(Solved) Fix Status-command hint output inconsistently split between stdout and stderr [1 pull requests, 1 comments, 2 participants]