fleet start prints a raw Node stack trace over the top of a precise diagnosis #1251

Open
opened 2026-08-16 06:06:01 +00:00 by fred · 1 comment
Collaborator

Summary

When a fleet unit fails to start, mosaic fleet start prints a raw Node stack trace. The precise,
actionable diagnosis exists — but only in the journal, where the operator has to know to go look.

What the operator sees

file:///home/mosaic/.npm-global/lib/node_modules/@mosaicstack/mosaic/dist/commands/fleet.js:1989
        throw new Error(result.stderr || result.stdout || `Command failed: ${command.join(' ')}`);
              ^

Error: Job for [email protected] failed because the control process exited with error code.
See "systemctl --user status [email protected]" and "journalctl --user -xeu ..." for details.

    at runChecked (.../dist/commands/fleet.js:1989:15)
    at async Command.<anonymous> (.../dist/commands/fleet.js:1242:17)

Node.js v22.23.2

What the journal already knows

ERROR: agent launch aborted: code=missing-binary agent=orchestrator
  'claude' is not on the pane PATH (/home/mosaic/.npm-global/bin:/usr/local/bin:/usr/bin:/bin)

and, one blocker later:

ERROR: agent launch aborted: code=pane-did-not-survive agent=orchestrator
  the pane exited immediately and tmux destroyed the session;
  run 'mosaic yolo claude' in /home/mosaic/src to see why

These messages are excellent. They name the failure class, the agent, and the next command to
run. They are wasted: the CLI throws over the top of them and shows Node internals instead.

Why it matters

This is the last step of the greenfield path. An operator who has just installed Mosaic on a
clean box runs mosaic fleet start, and the first thing the product shows them is a stack trace
pointing into dist/. The actual problem in both cases above is mundane and self-correctable —
a missing package, an unauthenticated runtime — but nothing on screen says so.

Suggested fix

runChecked should catch the unit-start failure and, instead of rethrowing raw:

  1. Read the last few lines of journalctl --user -u <unit> for that invocation.
  2. Print the ERROR: agent launch aborted: code=… line verbatim if present.
  3. Exit non-zero with no stack trace.

Fall back to the current message only when no diagnostic line is found. Keep the trace behind
--verbose / DEBUG for developers.

Red-first: assert that a fleet start against a unit that fails with a known code= line prints
that line and does not print at runChecked.

Note

The non-zero exit itself is correct and is a recent improvement — this command used to report
success while every pane was dead. This issue is only about the surface, not the semantics.

## Summary When a fleet unit fails to start, `mosaic fleet start` prints a raw Node stack trace. The precise, actionable diagnosis exists — but only in the journal, where the operator has to know to go look. ## What the operator sees ``` file:///home/mosaic/.npm-global/lib/node_modules/@mosaicstack/mosaic/dist/commands/fleet.js:1989 throw new Error(result.stderr || result.stdout || `Command failed: ${command.join(' ')}`); ^ Error: Job for [email protected] failed because the control process exited with error code. See "systemctl --user status [email protected]" and "journalctl --user -xeu ..." for details. at runChecked (.../dist/commands/fleet.js:1989:15) at async Command.<anonymous> (.../dist/commands/fleet.js:1242:17) Node.js v22.23.2 ``` ## What the journal already knows ``` ERROR: agent launch aborted: code=missing-binary agent=orchestrator 'claude' is not on the pane PATH (/home/mosaic/.npm-global/bin:/usr/local/bin:/usr/bin:/bin) ``` and, one blocker later: ``` ERROR: agent launch aborted: code=pane-did-not-survive agent=orchestrator the pane exited immediately and tmux destroyed the session; run 'mosaic yolo claude' in /home/mosaic/src to see why ``` These messages are excellent. They name the failure class, the agent, and the next command to run. They are wasted: the CLI throws over the top of them and shows Node internals instead. ## Why it matters This is the last step of the greenfield path. An operator who has just installed Mosaic on a clean box runs `mosaic fleet start`, and the first thing the product shows them is a stack trace pointing into `dist/`. The actual problem in both cases above is mundane and self-correctable — a missing package, an unauthenticated runtime — but nothing on screen says so. ## Suggested fix `runChecked` should catch the unit-start failure and, instead of rethrowing raw: 1. Read the last few lines of `journalctl --user -u <unit>` for that invocation. 2. Print the `ERROR: agent launch aborted: code=… ` line verbatim if present. 3. Exit non-zero with no stack trace. Fall back to the current message only when no diagnostic line is found. Keep the trace behind `--verbose` / `DEBUG` for developers. Red-first: assert that a `fleet start` against a unit that fails with a known `code=` line prints that line and does not print `at runChecked`. ## Note The non-zero exit itself is correct and is a recent improvement — this command used to report success while every pane was dead. This issue is only about the surface, not the semantics.
Author
Collaborator

Same root as #1247 — fix them together. @scooby's read, and I agree: the raw stack trace here is the program.parse()-is-synchronous problem at cli.ts:622 that #1247 scopes around runChecked. One cause, two symptoms. Fixing either alone leaves the trace in place.

This pairing is the highest-value of the three CLI-surface bugs (#1249/#1250/#1251), because the diagnostics #1244 exists to produce are exactly the ones the stack trace buries. #1244 made fleet start fail honestly and print a precise code= line; right now the operator never sees it.

Flagging on both issues so it does not get half-solved twice.

**Same root as #1247 — fix them together.** @scooby's read, and I agree: the raw stack trace here is the `program.parse()`-is-synchronous problem at `cli.ts:622` that #1247 scopes around `runChecked`. One cause, two symptoms. Fixing either alone leaves the trace in place. This pairing is the highest-value of the three CLI-surface bugs (#1249/#1250/#1251), because the diagnostics #1244 exists to produce are exactly the ones the stack trace buries. #1244 made `fleet start` fail honestly and print a precise `code=` line; right now the operator never sees it. Flagging on both issues so it does not get half-solved twice.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1251