henrygd/beszel · error

%s returned status %d

Error message

%s returned status %d

What it means

checkHealth polls the hub's health endpoint and treats the service as healthy only when the HTTP status is exactly 200. Any other status (404, 403, 500, 502, 503) is reported with this error including the URL and received status, so callers can fail startup or keep wait-looping.

Source

Thrown at internal/cmd/hub/hub.go:99

	healthCmd.Flags().StringVar(&baseURL, "url", "", "base URL")
	healthCmd.MarkFlagRequired("url")
	return healthCmd
}

// checkHealth checks the health of the hub.
func checkHealth(baseURL string) error {
	client := &http.Client{
		Timeout: time.Second * 3,
	}
	healthURL := baseURL + "/api/health"
	resp, err := client.Get(healthURL)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		return fmt.Errorf("%s returned status %d", healthURL, resp.StatusCode)
	}
	return nil
}

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Check hub logs for startup errors; if still booting, retry — transient during rollout.
  2. Verify healthURL scheme/host/port/path matches the hub's actual health route; curl it from inside the network to compare.
  3. If a proxy returns 404, exempt the health endpoint from auth/routing rewrites.
  4. Confirm the port mapping points at the hub process; fix compose/port config and restart.

Example fix

// before
if resp.StatusCode != 200 {
	return fmt.Errorf("%s returned status %d", healthURL, resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
	return fmt.Errorf("%s returned status %d (hub may still be starting; check hub logs)", healthURL, resp.StatusCode)
} // pair with a retry/backoff loop in the caller
Defensive patterns

Strategy: retry

Validate before calling

// probe the endpoint yourself before declaring failure
resp, err := http.Get(healthURL)
if err != nil || resp.StatusCode != http.StatusOK {
	log.Printf("hub not ready yet (%v)", err)
}

Try / catch

var err error
for i := 0; i < 30; i++ {
	if err = checkHealth(healthURL); err == nil {
		break
	}
	time.Sleep(2 * time.Second) // hub may still be starting
}
if err != nil {
	log.Fatalf("health check failed: %v", err)
}

Prevention

When it happens

Trigger: GET healthURL returns a non-200 response: the hub is still starting, the URL/port points at the wrong service, a reverse proxy intercepts the path (404/502), or auth middleware blocks the health route.

Common situations: Docker healthcheck racing container startup (503 during boot); health path misconfigured behind nginx/Traefik; port mapped to another container; hub crashed and the platform returns 502/503.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/0ce634417f66249d. Report an issue: GitHub.