@@ -25,6 +25,25 @@ export type ErrorDisplayOptions = {
2525 verbose ?: boolean | undefined
2626}
2727
28+ /**
29+ * Append the `.cause` chain (up to 5 levels) to a base message so
30+ * non-debug users see the diagnostic context from wrapped errors.
31+ * Typed errors (AuthError, NetworkError, …) can also carry causes.
32+ */
33+ function appendCauseChain ( baseMessage : string , cause : unknown ) : string {
34+ const plainCauses : string [ ] = [ ]
35+ let walk : unknown = cause
36+ let walkDepth = 1
37+ while ( walk && walkDepth <= 5 ) {
38+ plainCauses . push ( walk instanceof Error ? walk . message : String ( walk ) )
39+ walk = walk instanceof Error ? walk . cause : undefined
40+ walkDepth ++
41+ }
42+ return plainCauses . length
43+ ? `${ baseMessage } : ${ plainCauses . join ( ': ' ) } `
44+ : baseMessage
45+ }
46+
2847/**
2948 * Format an error for display with polish and clarity.
3049 * Uses LOG_SYMBOLS and colors for visual hierarchy.
@@ -47,50 +66,38 @@ export function formatErrorForDisplay(
4766 if ( error . retryAfter ) {
4867 message += ` (retry after ${ error . retryAfter } s)`
4968 }
69+ message = appendCauseChain ( message , error . cause )
5070 } else if ( error instanceof AuthError ) {
5171 title = 'Authentication error'
52- message = error . message
72+ message = appendCauseChain ( error . message , error . cause )
5373 } else if ( error instanceof NetworkError ) {
5474 title = 'Network error'
5575 message = error . message
5676 if ( error . statusCode ) {
5777 message += ` (HTTP ${ error . statusCode } )`
5878 }
79+ message = appendCauseChain ( message , error . cause )
5980 } else if ( error instanceof FileSystemError ) {
6081 title = 'File system error'
6182 message = error . message
6283 if ( error . path ) {
6384 message += ` (${ error . path } )`
6485 }
86+ message = appendCauseChain ( message , error . cause )
6587 } else if ( error instanceof ConfigError ) {
6688 title = 'Configuration error'
6789 message = error . message
6890 if ( error . configKey ) {
6991 message += ` (key: ${ error . configKey } )`
7092 }
93+ message = appendCauseChain ( message , error . cause )
7194 } else if ( error instanceof InputError ) {
7295 title = 'Invalid input'
73- message = error . message
96+ message = appendCauseChain ( error . message , error . cause )
7497 body = error . body
7598 } else if ( error instanceof Error ) {
7699 title = opts . title || 'Unexpected error'
77- // Concatenate the cause chain into `message` (what non-debug users see)
78- // so diagnostic context from wrapped errors isn't silently dropped.
79- // `showStack` adds a richer formatted body with stack traces below.
80- message = error . message
81- const plainCauses : string [ ] = [ ]
82- let walk : unknown = error . cause
83- let walkDepth = 1
84- while ( walk && walkDepth <= 5 ) {
85- plainCauses . push (
86- walk instanceof Error ? walk . message : String ( walk ) ,
87- )
88- walk = walk instanceof Error ? walk . cause : undefined
89- walkDepth ++
90- }
91- if ( plainCauses . length ) {
92- message = `${ message } : ${ plainCauses . join ( ': ' ) } `
93- }
100+ message = appendCauseChain ( error . message , error . cause )
94101
95102 if ( showStack && error . stack ) {
96103 // Format stack trace with proper indentation.
0 commit comments