[BUG] One failed statusLine invocation erases the last rendered text — bar goes blank with no error (statusLineText set to undefined)

Status Open
Reported on v2.1.223
Maintainer reply None cached
Activity 1 comment · opened Aug 6, 2026

Summary

When a custom statusLine command fails once — non-zero exit, spawn failure, or empty stdout — Claude Code does not keep the previously rendered text. It actively clears the internal statusLineText to undefined, rendering a blank status bar with no error surfaced anywhere. On a loaded machine (several parallel agent sessions → occasional transient spawn failures), long-lived sessions flicker between a rendered bar and a blank one.

This is the intermittent/transient variant of #76380 (persistent failure → permanently blank). Root cause below covers both.

Environment

  • Claude Code 2.1.223 (build 2026-08-05T18:12:31Z, git sha 4535f697); same code present in 2.1.222
  • macOS (darwin arm64, Darwin 25.6.0), Ghostty 1.3.1
  • Config: "statusLine": { "type": "command", "command": "python3 ~/.claude/scripts/statusline.py" }

Root cause (from bundle inspection of 2.1.223)

The command executor (minified jda) returns undefined for every failure mode:

async function jda(e, t, r) {
  ...
  let s = await oJo(n, "StatusLine", ...);
  if (s.aborted) return;                       // undefined
  ...
  if (s.status === 0) {
    let l = s.stdout.trim()....join("\n");
    if (l) { ...; return l }                   // only success path
  }
  ...
  return;                                      // nonzero exit / spawn failure / empty stdout → undefined
} catch { return }                             // exec error → undefined

The result handler (minified mHT) forwards that undefined into the store unconditionally — only the abort-signal path preserves the old text:

let l = await r();
if (t.aborted) return;   // abort keeps stale text…
i(l);                    // …but a failure commits `undefined`
onResult: (Y) => { setState((X) => X.statusLineText === Y ? X : { ...X, statusLineText: Y }) }

Render branch: a ? <text> : showSpace() ? " " : null → blank row. No error reaches the UI; stderr only goes to debug logging.

So a single transient failure erases the last good status text. It stays blank until the next successful run (next message-driven refresh tick, a statusLine.command string change, or the refreshInterval timer if configured).

Evidence it's not the user command

I wrapped the configured command in a logging shim that records START/END/exit-code/duration per invocation. The underlying script always exits 0 in ~100–200 ms and never prints empty output (it has a catch-all that prints a fallback line). Blank episodes correlate with invocation-level failures under load, not with script behavior. Also reproducible reasoning-wise via #76380's scenario (exit 127 → permanent blank).

Expected

Stale-on-error: a failed refresh should keep the last successfully rendered text (optionally with a warning in debug logs). Clearing the bar should be reserved for deliberate unconfiguration. Concretely, in mHT: if (l === undefined) return; — the same treatment the abort path already gets.

Actual

statusLineText is set to undefined → blank bar, silently.

Related observation

statusLine.refreshInterval (seconds; Math.max(1, K) * 1000 → interval timer) exists in 2.1.223 and works — "refreshInterval": 5 makes blanks self-heal within 5 s and hot-reloads without restart. It appears to be undocumented on https://code.claude.com/docs/en/statusline; documenting it would give users a mitigation, though stale-on-error is the real fix.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗