charmbracelet/crush · error

status code %d: %s

Error message

status code %d: %s

What it means

checkStatus validates HTTP responses from the client API. When the status code is not in the accepted list and the response body contains an error message, it produces "status code %d: %s" with the server-provided message. This is the client-side representation of a server-side HTTP error.

Source

Thrown at internal/client/errors.go:53

	// failure as transient.
	ErrUnsupported = errors.New("unsupported by the running server")
)

// checkStatus returns nil when rsp's status code is one of ok
// (http.StatusOK when none are given). Otherwise it returns an error
// carrying the status code and, when the body decodes as a proto.Error,
// the server-provided message. Statuses that callers act on are wrapped
// in the matching sentinel. checkStatus may consume the response body.
func checkStatus(rsp *http.Response, ok ...int) error {
	if len(ok) == 0 {
		ok = []int{http.StatusOK}
	}
	if slices.Contains(ok, rsp.StatusCode) {
		return nil
	}
	var err error
	if msg := decodeErrorMessage(rsp.Body); msg != "" {
		err = fmt.Errorf("status code %d: %s", rsp.StatusCode, msg)
	} else {
		err = fmt.Errorf("status code %d", rsp.StatusCode)
	}
	switch rsp.StatusCode {
	case http.StatusNotFound:
		return fmt.Errorf("%w: %w", ErrNotFound, err)
	case http.StatusServiceUnavailable:
		return fmt.Errorf("%w: %w", ErrServerShuttingDown, err)
	}
	return err
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Read the message after the colon — it is the server's own error text and usually names the exact problem.
  2. Fix the request payload/parameters indicated by the message (e.g. invalid workspace fields).
  3. Re-authenticate if the status indicates 401/403.
  4. Check client/server version compatibility if the endpoint is reported as unknown or the request shape is rejected.

Example fix

// before: treating any error generically
ws, err := client.CreateWorkspace(ctx, ws)
if err != nil {
	return err
}
// after: inspect status/message for actionable handling
ws, err := client.CreateWorkspace(ctx, ws)
if err != nil {
	var statusErr *client.StatusError
	if errors.As(err, &statusErr) && statusErr.StatusCode == http.StatusUnauthorized {
		return refreshAuthAndRetry(ctx)
	}
	return fmt.Errorf("create workspace rejected by server: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate request payload before sending
if ws == nil || ws.Path == "" {
	return errors.New("workspace path is required")
}

Type guard

func isStatusError(err error) (statusCode int, msg string, ok bool) {
	// Parse "status code %d: %s" produced by checkStatus
	const prefix = "status code "
	s := err.Error()
	if !strings.HasPrefix(s, prefix) {
		return 0, "", false
	}
	rest := s[len(prefix):]
	if idx := strings.IndexByte(rest, ':'); idx >= 0 {
		code, e := strconv.Atoi(strings.TrimSpace(rest[:idx]))
		return code, strings.TrimSpace(rest[idx+1:]), e == nil
	}
	code, e := strconv.Atoi(strings.TrimSpace(rest))
	return code, "", e == nil
}

Try / catch

result, err := client.CreateWorkspace(ctx, ws)
if err != nil {
	if code, msg, ok := isStatusError(err); ok {
		switch code {
		http.StatusUnauthorized, http.StatusForbidden:
			return reauthenticate(ctx)
		default:
			return fmt.Errorf("server rejected request (%d): %s", code, msg)
		}
	}
	return err
}

Prevention

When it happens

Trigger: Any client call routed through checkStatus (RetireClient, CreateWorkspace, GetWorkspace, SetCurrentSession, SubscribeEvents, and anonymous handlers) receiving a non-OK status where decodeErrorMessage extracts a message from the body — e.g. 400/401/403/409/500 with a JSON error payload.

Common situations: Sending an invalid workspace payload (400), missing or expired auth (401/403), server-side panic (500), or a client/server version mismatch causing the server to reject the request.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/e6e94e2a00cfcba4. Report an issue: GitHub.