{"record":{"id":"c1c709e8ca11956d","repo":"charmbracelet/crush","slug":"status-code-d","errorCode":null,"errorMessage":"status code %d","messagePattern":"status code (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/errors.go","lineNumber":55,"sourceCode":")\n\n// checkStatus returns nil when rsp's status code is one of ok\n// (http.StatusOK when none are given). Otherwise it returns an error\n// carrying the status code and, when the body decodes as a proto.Error,\n// the server-provided message. Statuses that callers act on are wrapped\n// in the matching sentinel. checkStatus may consume the response body.\nfunc checkStatus(rsp *http.Response, ok ...int) error {\n\tif len(ok) == 0 {\n\t\tok = []int{http.StatusOK}\n\t}\n\tif slices.Contains(ok, rsp.StatusCode) {\n\t\treturn nil\n\t}\n\tvar err error\n\tif msg := decodeErrorMessage(rsp.Body); msg != \"\" {\n\t\terr = fmt.Errorf(\"status code %d: %s\", rsp.StatusCode, msg)\n\t} else {\n\t\terr = fmt.Errorf(\"status code %d\", rsp.StatusCode)\n\t}\n\tswitch rsp.StatusCode {\n\tcase http.StatusNotFound:\n\t\treturn fmt.Errorf(\"%w: %w\", ErrNotFound, err)\n\tcase http.StatusServiceUnavailable:\n\t\treturn fmt.Errorf(\"%w: %w\", ErrServerShuttingDown, err)\n\t}\n\treturn err\n}\n","sourceCodeStart":37,"sourceCodeEnd":65,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/client/errors.go#L37-L65","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: opaque handling\nif err := checkStatus(rsp); err != nil {\n\treturn err\n}\n// after: log status and inspect body directly when message is absent\nif err := checkStatus(rsp); err != nil {\n\tlog.Printf(\"request failed with unexplained status; check server logs and base URL: %v\", err)\n\treturn err\n}","handlingStrategy":"retry","validationCode":"// Health-check the server before making real calls\nresp, err := http.Get(baseURL + \"/health\")\nif err != nil || resp.StatusCode != http.StatusOK {\n\treturn errors.New(\"daemon is not reachable; start it before calling the client\")\n}","typeGuard":"func isUnexplainedStatusError(err error) bool {\n\treturn err != nil && strings.HasPrefix(err.Error(), \"status code \") && !strings.Contains(err.Error(), \": \")\n}","tryCatchPattern":"resp, err := doRequest(ctx)\nif err != nil {\n\tif isUnexplainedStatusError(err) {\n\t\t// No message from server: transient infra issue likely; retry with backoff\n\t\treturn retryWithBackoff(ctx, 3, doRequest)\n\t}\n\treturn err\n}","preventionTips":["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."],"tags":["http","api","client","status-code"],"backgroundTag":"http-error-response","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}