juanfont/headscale · error

checking health: %w

Error message

checking health: %w

What it means

Transport error from 'headscale health': the GET to the health endpoint failed before a response was parsed (client.HealthWithResponse returned err). Ironic but informative — the command whose purpose is to report server health fails when the server is entirely unreachable, and this error is the signal for that case (exit code becomes non-zero).

Source

Thrown at cmd/headscale/cli/health.go:23

	"fmt"
	"net/http"

	clientv1 "github.com/juanfont/headscale/gen/client/v1"
	"github.com/spf13/cobra"
)

func init() {
	rootCmd.AddCommand(healthCmd)
}

var healthCmd = &cobra.Command{
	Use:   "health",
	Short: "Check the health of the Headscale server",
	Long:  "Check the health of the Headscale server. This command will return an exit code of 0 if the server is healthy, or 1 if it is not.",
	RunE: clientRunE(func(ctx context.Context, client *clientv1.ClientWithResponses, cmd *cobra.Command, args []string) error {
		resp, err := client.HealthWithResponse(ctx)
		if err != nil {
			return fmt.Errorf("checking health: %w", err)
		}

		if resp.StatusCode() != http.StatusOK {
			return apiError(resp.StatusCode(), resp.ApplicationproblemJSONDefault)
		}

		return printOutput(cmd, resp.JSON200, "")
	}),
}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Confirm the headscale process is actually running (systemctl status / ps)
  2. Compare the CLI's configured address with the server's listen address
  3. Check TLS: if the server uses self-signed certs, configure the CA in the CLI socket settings
  4. Interpret the wrapped error — dial tcp refused, x509, and no such host each have distinct fixes
Defensive patterns

Strategy: retry

Validate before calling

// probe before relying on the CLI health command in scripts
if err := probeTCP(addr, 2*time.Second); err != nil {
	fmt.Fprintf(os.Stderr, "server at %s unreachable: %v\n", addr, err)
	os.Exit(1)
}

Try / catch

if err := healthCmd.Execute(); err != nil {
	// non-zero exit is the intended signal; distinguish transport (server down) from unhealthy response
	if strings.Contains(err.Error(), "checking health") { /* server unreachable */ }
}

Prevention

When it happens

Trigger: Running 'headscale health' when the server is not started, is bound to a different address/port than the CLI targets, TLS is misconfigured, or DNS for the configured server URL fails.

Common situations: First-line debugging after a failed headscale start; systemd service crashed; CLI config still pointing at default 127.0.0.1:50443 while the server listens elsewhere; monitoring probes using the CLI against a moved endpoint.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/6bc4296a806a5810. Report an issue: GitHub.