Skip to content

Commit 8b30f94

Browse files
committed
improve some cli errors
1 parent e3ad958 commit 8b30f94

File tree

4 files changed

+39
-16
lines changed

4 files changed

+39
-16
lines changed

cli/root.go

+20-10
Original file line numberDiff line numberDiff line change
@@ -1035,8 +1035,10 @@ func cliHumanFormatError(err error, opts *formatOpts) string {
10351035
if opts == nil {
10361036
opts = &formatOpts{}
10371037
}
1038+
if err == nil {
1039+
return "<nil>"
1040+
}
10381041

1039-
//nolint:errorlint
10401042
if multi, ok := err.(interface{ Unwrap() []error }); ok {
10411043
multiErrors := multi.Unwrap()
10421044
if len(multiErrors) == 1 {
@@ -1048,16 +1050,28 @@ func cliHumanFormatError(err error, opts *formatOpts) string {
10481050

10491051
// First check for sentinel errors that we want to handle specially.
10501052
// Order does matter! We want to check for the most specific errors first.
1051-
var sdkError *codersdk.Error
1052-
if errors.As(err, &sdkError) {
1053+
//var sdkError *codersdk.Error
1054+
//if errors.As(err, &sdkError) {
1055+
if sdkError, ok := err.(*codersdk.Error); ok {
10531056
return formatCoderSDKError(sdkError, opts)
10541057
}
10551058

1056-
var cmdErr *clibase.RunCommandError
1057-
if errors.As(err, &cmdErr) {
1059+
//var cmdErr *clibase.RunCommandError
1060+
//if errors.As(err, &cmdErr) {
1061+
if cmdErr, ok := err.(*clibase.RunCommandError); ok {
10581062
return formatRunCommandError(cmdErr, opts)
10591063
}
10601064

1065+
uw, ok := err.(interface{ Unwrap() error })
1066+
if ok {
1067+
msg := cliHumanFormatError(uw.Unwrap(), opts)
1068+
if msg != "" {
1069+
return msg
1070+
}
1071+
}
1072+
// If we got here, that means the error is not anything special. Just format
1073+
// it as is.
1074+
10611075
// Default just printing the error. Use +v for verbose to handle stack
10621076
// traces of xerrors.
10631077
if opts.Verbose {
@@ -1112,11 +1126,7 @@ func formatRunCommandError(err *clibase.RunCommandError, opts *formatOpts) strin
11121126
var str strings.Builder
11131127
_, _ = str.WriteString(pretty.Sprint(headLineStyle(), fmt.Sprintf("Encountered an error running %q", err.Cmd.FullName())))
11141128

1115-
msgString := fmt.Sprintf("%v", err.Err)
1116-
if opts.Verbose {
1117-
// '%+v' includes stack traces
1118-
msgString = fmt.Sprintf("%+v", err.Err)
1119-
}
1129+
msgString := cliHumanFormatError(err.Err, opts)
11201130
_, _ = str.WriteString("\n")
11211131
_, _ = str.WriteString(pretty.Sprint(tailLineStyle(), msgString))
11221132
return str.String()

codersdk/client.go

+13-4
Original file line numberDiff line numberDiff line change
@@ -323,14 +323,24 @@ func (c *Client) Request(ctx context.Context, method, path string, body interfac
323323
return resp, err
324324
}
325325

326+
// ExpectJSONMime is a helper function that will assert the content type
327+
// of the response is application/json.
328+
func ExpectJSONMime(res *http.Response) error {
329+
contentType := res.Header.Get("Content-Type")
330+
mimeType := parseMimeType(contentType)
331+
if mimeType != "application/json" {
332+
return xerrors.Errorf("unexpected non-JSON response %q", contentType)
333+
}
334+
return nil
335+
}
336+
326337
// ReadBodyAsError reads the response as a codersdk.Response, and
327338
// wraps it in a codersdk.Error type for easy marshaling.
328339
func ReadBodyAsError(res *http.Response) error {
329340
if res == nil {
330341
return xerrors.Errorf("no body returned")
331342
}
332343
defer res.Body.Close()
333-
contentType := res.Header.Get("Content-Type")
334344

335345
var requestMethod, requestURL string
336346
if res.Request != nil {
@@ -352,8 +362,7 @@ func ReadBodyAsError(res *http.Response) error {
352362
return xerrors.Errorf("read body: %w", err)
353363
}
354364

355-
mimeType := parseMimeType(contentType)
356-
if mimeType != "application/json" {
365+
if mimeErr := ExpectJSONMime(res); mimeErr != nil {
357366
if len(resp) > 2048 {
358367
resp = append(resp[:2048], []byte("...")...)
359368
}
@@ -365,7 +374,7 @@ func ReadBodyAsError(res *http.Response) error {
365374
method: requestMethod,
366375
url: requestURL,
367376
Response: Response{
368-
Message: fmt.Sprintf("unexpected non-JSON response %q", contentType),
377+
Message: mimeErr.Error(),
369378
Detail: string(resp),
370379
},
371380
Helper: helpMessage,

codersdk/deployment.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2065,7 +2065,7 @@ func (c *Client) BuildInfo(ctx context.Context) (BuildInfoResponse, error) {
20652065
}
20662066
defer res.Body.Close()
20672067

2068-
if res.StatusCode != http.StatusOK {
2068+
if res.StatusCode != http.StatusBadRequest || ExpectJSONMime(res) != nil {
20692069
return BuildInfoResponse{}, ReadBodyAsError(res)
20702070
}
20712071

enterprise/wsproxy/wsproxy.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"crypto/tls"
66
"crypto/x509"
7+
"errors"
78
"fmt"
89
"net/http"
910
"net/url"
@@ -157,7 +158,10 @@ func New(ctx context.Context, opts *Options) (*Server, error) {
157158
// TODO: Probably do some version checking here
158159
info, err := client.SDKClient.BuildInfo(ctx)
159160
if err != nil {
160-
return nil, xerrors.Errorf("failed to fetch build info from %q: %w", opts.DashboardURL, err)
161+
return nil, errors.Join(
162+
fmt.Errorf("unable to fetch build info from primary coderd. Are you sure %q is a coderd instance?", opts.DashboardURL),
163+
err,
164+
)
161165
}
162166
if info.WorkspaceProxy {
163167
return nil, xerrors.Errorf("%q is a workspace proxy, not a primary coderd instance", opts.DashboardURL)

0 commit comments

Comments
 (0)