charmbracelet/crush · error
status code %d
Error message
status code %d
What it means
checkStatus produces this bare "status code %d" error when the response status is not accepted AND the body contains no decodable error message. The caller only learns the numeric status; the server gave no usable error payload.
Source
Thrown at internal/client/errors.go:55
)
// 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
- Map the numeric status to its meaning (404 = wrong endpoint/not running, 502/503 = upstream down).
- Verify the server is running the expected version at the configured address.
- Check server/proxy logs for the request to find why no error body was returned.
- Confirm the base URL is correct — a 404 here often means the path or port is wrong.
Example fix
// before: opaque handling
if err := checkStatus(rsp); err != nil {
return err
}
// after: log status and inspect body directly when message is absent
if err := checkStatus(rsp); err != nil {
log.Printf("request failed with unexplained status; check server logs and base URL: %v", err)
return err
} Defensive patterns
Strategy: retry
Validate before calling
// Health-check the server before making real calls
resp, err := http.Get(baseURL + "/health")
if err != nil || resp.StatusCode != http.StatusOK {
return errors.New("daemon is not reachable; start it before calling the client")
} Type guard
func isUnexplainedStatusError(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "status code ") && !strings.Contains(err.Error(), ": ")
} Try / catch
resp, err := doRequest(ctx)
if err != nil {
if isUnexplainedStatusError(err) {
// No message from server: transient infra issue likely; retry with backoff
return retryWithBackoff(ctx, 3, doRequest)
}
return err
} Prevention
- Add a startup health check before issuing client calls.
- Configure proxies/load balancers to forward the server's JSON error bodies.
- Retry transient statuses (502/503/504) with exponential backoff.
- Verify the base URL and port during setup; bare 404s usually mean a wrong address or old server.
When it happens
Trigger: Any checkStatus-guarded call (RetireClient, CreateWorkspace, GetWorkspace, SetCurrentSession, SubscribeEvents) receiving a non-OK response with an empty, non-JSON, or message-less body — e.g. a bare 502 from a proxy, a 404 with an empty body, or a connection reset mid-response.
Common situations: The daemon is behind a load balancer returning HTML/empty errors; the server crashed without writing a JSON error; an old server version predating the error-message format; a proxy stripping response bodies.
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
- status code %d: %s
- unexpected status code: %d
- failed to list workspaces: status code %d
- failed to get MCP pending auth: status code %d
- failed to get MCP auth URL: status code %d
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/c1c709e8ca11956d.
Report an issue: GitHub.