charmbracelet/crush · error

unexpected status code: %d

Error message

unexpected status code: %d

What it means

Returned by doGet when the Hyper API responds with a status code other than 200, 304, or 401. 304 and 401 have dedicated handling (ErrNotModified and errUnauthorized), so anything else — 500, 502, 503, 404, 429 — falls into this generic error.

Source

Thrown at internal/config/hyper.go:174

	}

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return result, fmt.Errorf("failed to make request: %w", err)
	}
	defer resp.Body.Close() //nolint:errcheck

	if resp.StatusCode == http.StatusNotModified {
		return result, catwalk.ErrNotModified
	}

	if resp.StatusCode == http.StatusUnauthorized {
		return result, errUnauthorized
	}

	if resp.StatusCode != http.StatusOK {
		return result, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		return result, fmt.Errorf("failed to decode response: %w", err)
	}

	return result, nil
}

// errUnauthorized is a sentinel for HTTP 401 responses from the Hyper API.
var errUnauthorized = errors.New("unauthorized")

// isHTTPUnauthorized reports whether err is or wraps errUnauthorized.
func isHTTPUnauthorized(err error) bool {
	return errors.Is(err, errUnauthorized)
}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the Hyper API status/uptime for outages before debugging client code.
  2. Log the status code and response body to identify whether it's 4xx (client) or 5xx (server).
  3. For 429, add backoff/retry with respect for Retry-After headers.
  4. Verify the endpoint URL and API version are current.

Example fix

// before
cfg, err := config.Get()
// after: retry on transient server errors
for i := 0; i < 3; i++ {
	cfg, err = config.Get()
	if err == nil || !strings.Contains(err.Error(), "unexpected status code: 5") {
		break
	}
	time.Sleep(time.Duration(1<<i) * time.Second)
}
Defensive patterns

Strategy: retry

Validate before calling

// no pre-call validation possible; probe endpoint health instead
// curl -s -o /dev/null -w '%{http_code}' https://hyper-endpoint/health

Type guard

var scErr *statusCodeError
if errors.As(err, &scErr) && scErr.Code >= 500 { /* transient */ }

Try / catch

if err != nil && strings.Contains(err.Error(), "unexpected status code") {
	// log code, retry on 5xx/429 with backoff, surface 4xx to user
}

Prevention

When it happens

Trigger: Calling config.Get when the Hyper API returns e.g. HTTP 500 (server error), 502/503 (gateway outage), 404 (wrong path/endpoint version), or 429 (rate limited).

Common situations: Hyper API outage or degraded service; client pointing at a stale/moved endpoint; hitting rate limits from frequent polling; API version changes removing the endpoint.

Related errors


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