@@ -1016,7 +1016,7 @@ type prettyErrorFormatter struct {
1016
1016
// format formats the error to the console. This error should be human
1017
1017
// readable.
1018
1018
func (p * prettyErrorFormatter ) format (err error ) {
1019
- output := cliHumanFormatError (err , & formatOpts {
1019
+ output , _ := cliHumanFormatError (err , & formatOpts {
1020
1020
Verbose : p .verbose ,
1021
1021
})
1022
1022
// always trail with a newline
@@ -1030,13 +1030,23 @@ type formatOpts struct {
1030
1030
const indent = " "
1031
1031
1032
1032
// cliHumanFormatError formats an error for the CLI. Newlines and styling are
1033
- // included.
1034
- func cliHumanFormatError (err error , opts * formatOpts ) string {
1033
+ // included. The second return value is true if the error is special and the error
1034
+ // chain has custom formatting applied.
1035
+ //
1036
+ // If you change this code, you can use the cli "example-errors" tool to
1037
+ // verify all errors still look ok.
1038
+ //
1039
+ // go run main.go exp example-error <type>
1040
+ // go run main.go exp example-error api
1041
+ // go run main.go exp example-error cmd
1042
+ // go run main.go exp example-error multi-error
1043
+ // go run main.go exp example-error validation
1044
+ func cliHumanFormatError (err error , opts * formatOpts ) (string , bool ) {
1035
1045
if opts == nil {
1036
1046
opts = & formatOpts {}
1037
1047
}
1038
1048
if err == nil {
1039
- return "<nil>"
1049
+ return "<nil>" , true
1040
1050
}
1041
1051
1042
1052
if multi , ok := err .(interface { Unwrap () []error }); ok {
@@ -1045,40 +1055,41 @@ func cliHumanFormatError(err error, opts *formatOpts) string {
1045
1055
// Format as a single error
1046
1056
return cliHumanFormatError (multiErrors [0 ], opts )
1047
1057
}
1048
- return formatMultiError (multiErrors , opts )
1058
+ return formatMultiError (multiErrors , opts ), false
1049
1059
}
1050
1060
1051
1061
// First check for sentinel errors that we want to handle specially.
1052
1062
// Order does matter! We want to check for the most specific errors first.
1053
1063
//var sdkError *codersdk.Error
1054
1064
//if errors.As(err, &sdkError) {
1055
1065
if sdkError , ok := err .(* codersdk.Error ); ok {
1056
- return formatCoderSDKError (sdkError , opts )
1066
+ return formatCoderSDKError (sdkError , opts ), false
1057
1067
}
1058
1068
1059
1069
//var cmdErr *clibase.RunCommandError
1060
1070
//if errors.As(err, &cmdErr) {
1061
1071
if cmdErr , ok := err .(* clibase.RunCommandError ); ok {
1062
- return formatRunCommandError (cmdErr , opts )
1072
+ return formatRunCommandError (cmdErr , opts ), false
1063
1073
}
1064
1074
1065
1075
uw , ok := err .(interface { Unwrap () error })
1066
1076
if ok {
1067
- msg := cliHumanFormatError (uw .Unwrap (), opts )
1068
- if msg != "" {
1069
- return msg
1077
+ msg , special := cliHumanFormatError (uw .Unwrap (), opts )
1078
+ if special {
1079
+ return msg , special
1070
1080
}
1071
1081
}
1072
- // If we got here, that means the error is not anything special. Just format
1073
- // it as is.
1082
+ // If we got here, that means that the wrapped error chain does not have
1083
+ // any special formatting below it. So we want to return the topmost non-special
1084
+ // error (which is 'err')
1074
1085
1075
1086
// Default just printing the error. Use +v for verbose to handle stack
1076
1087
// traces of xerrors.
1077
1088
if opts .Verbose {
1078
- return pretty .Sprint (headLineStyle (), fmt .Sprintf ("%+v" , err ))
1089
+ return pretty .Sprint (headLineStyle (), fmt .Sprintf ("%+v" , err )), false
1079
1090
}
1080
1091
1081
- return pretty .Sprint (headLineStyle (), fmt .Sprintf ("%v" , err ))
1092
+ return pretty .Sprint (headLineStyle (), fmt .Sprintf ("%v" , err )), false
1082
1093
}
1083
1094
1084
1095
// formatMultiError formats a multi-error. It formats it as a list of errors.
@@ -1092,7 +1103,8 @@ func cliHumanFormatError(err error, opts *formatOpts) string {
1092
1103
func formatMultiError (multi []error , opts * formatOpts ) string {
1093
1104
var errorStrings []string
1094
1105
for _ , err := range multi {
1095
- errorStrings = append (errorStrings , cliHumanFormatError (err , opts ))
1106
+ msg , _ := cliHumanFormatError (err , opts )
1107
+ errorStrings = append (errorStrings , msg )
1096
1108
}
1097
1109
1098
1110
// Write errors out
@@ -1126,7 +1138,7 @@ func formatRunCommandError(err *clibase.RunCommandError, opts *formatOpts) strin
1126
1138
var str strings.Builder
1127
1139
_ , _ = str .WriteString (pretty .Sprint (headLineStyle (), fmt .Sprintf ("Encountered an error running %q" , err .Cmd .FullName ())))
1128
1140
1129
- msgString := cliHumanFormatError (err .Err , opts )
1141
+ msgString , _ := cliHumanFormatError (err .Err , opts )
1130
1142
_ , _ = str .WriteString ("\n " )
1131
1143
_ , _ = str .WriteString (pretty .Sprint (tailLineStyle (), msgString ))
1132
1144
return str .String ()
0 commit comments