fix: centralize error handling with CliError and global handler#144
fix: centralize error handling with CliError and global handler#144scottlovegrove merged 2 commits intomainfrom
Conversation
Introduce a CliError class with typed error codes and a global error handler in index.ts that formats errors as structured JSON when --json is passed. This replaces the inconsistent mix of throw new Error(), console.error + process.exit(1), and console.error + process.exitCode patterns across ~47 files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
doistbot
left a comment
There was a problem hiding this comment.
This PR is a fantastic refactoring effort that centralizes error handling and standardizes on CliError to significantly enhance the CLI's maintainability and output reliability. The unified global handler successfully eliminates inconsistent exit patterns and improves the overall experience for both text and JSON outputs. A few minor areas were noted for refinement, specifically regarding the preservation of stack traces for unexpected runtime errors, consistently applying NoTokenError across all unauthenticated paths, handling raw 401 errors gracefully in the status command, and adding missing codes to the ErrorCode union.
- Preserve stack traces for unexpected (non-CliError) errors in text mode - Use NoTokenError consistently on all no-token paths in getApiToken - Catch NoTokenError and 401s in auth status to normalize auth errors - Add UNKNOWN_AGENT to ErrorCode union Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## [2.23.2](v2.23.1...v2.23.2) (2026-04-05) ### Bug Fixes * centralize error handling with CliError and global handler ([#144](#144)) ([b1ef8d3](b1ef8d3))
|
🎉 This PR is included in version 2.23.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Summary
CliErrorclass (src/lib/errors.ts) with typed error codes, optional hints, and anerror/infotype for controlling output colorsrc/index.tsthat formats all unhandled errors as structured JSON ({"error":{"code","message","hints"}}) when--jsonis passed, or as formatted text otherwisethrow new Error(),console.error() + process.exit(1), andconsole.error() + process.exitCode = 1patterns tothrow new CliError(code, message, hints?)NoTokenErrorsubclass (typeinfo, renders yellow) for the "not authenticated" caseprocess.exit(1)calls remain in the sourceTest plan
npm run type-checkpassesnpm run lint:checkpassesCliError.codeinstead of console output)tw thread view invalid-refshows formatted error texttw thread view invalid-ref --jsonshows{"error":{"code":"INVALID_REF","message":"..."}}tw auth statuswhen unauthenticated shows yellow info-style errortw auth status --jsonwhen unauthenticated shows structured JSON error🤖 Generated with Claude Code