Skip to content

cli: errors print only message, swallowing stack and cause chain #25

@joewalker

Description

@joewalker

Observed behavior

src/cli.ts ends with:

main().catch((err: unknown) => {
  console.error(err instanceof Error ? err.message : String(err));
  process.exitCode = 1;
});

Only err.message reaches the terminal. The stack trace, any cause chain attached via new Error('...', { cause }), and any custom properties (e.g. err.code for ENOENT) are dropped. For a CLI that has multiple async layers (config loading, agent invocation, reporter writes, git operations), this makes it noticeably harder than it should be to diagnose failures: the user sees a single line like disk full with no indication of which call site produced it.

This is inconsistent with the --verbose flag's stated purpose ("Controls verbose diagnostic logging to stderr.") which suggests verbose mode should expose more diagnostic detail, but currently the verbose flag has no effect on the catch handler.

Expected behavior

Either always log the full err.stack (and walk err.cause if present), or at least log the stack/cause when --verbose is in effect. The single-line message should remain for the non-verbose default if brevity is the goal.

Minimal reproduction

Configure a reporter whose append throws new Error('disk full', { cause: new Error('underlying ENOSPC') }), run the CLI, and observe that only disk full is printed; the cause is lost and no stack is shown.

Suggested fix

main().catch((err: unknown) => {
  if (err instanceof Error) {
    console.error(verboseFromArgv() ? (err.stack ?? err.message) : err.message);
    // Walk err.cause if present
    let cause = (err as { cause?: unknown }).cause;
    while (cause instanceof Error) {
      console.error('Caused by:', cause.stack ?? cause.message);
      cause = (cause as { cause?: unknown }).cause;
    }
  } else {
    console.error(String(err));
  }
  process.exitCode = 1;
});

The simplest version: always console.error(err instanceof Error ? (err.stack ?? err.message) : String(err)).

Metadata

Metadata

Assignees

No one assigned

    Labels

    S4Clean-ups or nits with low behavioral riskbugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions