juanfont/headscale · error
listing api keys: %w
Error message
listing api keys: %w
What it means
Wrapped error from the 'headscale apikeys list' Cobra subcommand when client.ListApiKeysWithResponse returns a transport-level error — i.e., the HTTP request to the headscale server failed before a response was parsed (connection refused, TLS failure, DNS, timeout, malformed URL).
Source
Thrown at cmd/headscale/cli/api_key.go:50
deleteAPIKeyCmd.Flags().StringP("prefix", "p", "", "ApiKey prefix")
deleteAPIKeyCmd.Flags().Uint64P("id", "i", 0, "ApiKey ID")
apiKeysCmd.AddCommand(deleteAPIKeyCmd)
}
var apiKeysCmd = &cobra.Command{
Use: "apikeys",
Short: "Handle the Api keys in Headscale",
Aliases: []string{"apikey", "api"},
}
var listAPIKeys = &cobra.Command{
Use: cmdList,
Short: "List the Api keys for headscale",
Aliases: []string{"ls", cmdShow},
RunE: clientRunE(func(ctx context.Context, client *clientv1.ClientWithResponses, cmd *cobra.Command, args []string) error {
resp, err := client.ListApiKeysWithResponse(ctx)
if err != nil {
return fmt.Errorf("listing api keys: %w", err)
}
if resp.StatusCode() != http.StatusOK {
return apiError(resp.StatusCode(), resp.ApplicationproblemJSONDefault)
}
apiKeys := resp.JSON200.ApiKeys
return printListOutput(cmd, apiKeys, func() error {
rows := make([][]string, 0, len(apiKeys))
for _, key := range apiKeys {
expiration := "-"
if key.Expiration != nil {
expiration = ColourTime(*key.Expiration)
}
var created string
if key.CreatedAt != nil {View on GitHub (pinned to 565fd254d0)
Solutions
- Verify the server is up: 'headscale health' or curl the --address endpoint
- Check the CLI configuration (config file or HS_ADDRESS / --address) points at the server's actual bind address
- If TLS is enabled, ensure the CLI trusts the server certificate (ca_cert in the socket config or --tls-ca)
- Look at the wrapped error text — connection refused vs x509 vs timeout each points to a different fix
Defensive patterns
Strategy: retry
Validate before calling
// before listing, confirm the server endpoint answers
req, _ := http.NewRequest(http.MethodGet, addr+"/health", nil)
if resp, err := http.DefaultClient.Do(req); err != nil || resp.StatusCode != 200 {
return fmt.Errorf("server not reachable at %s", addr)
} Type guard
func isTransportError(err error) bool {
var netErr net.Error
return errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded)
} Try / catch
resp, err := client.ListApiKeysWithResponse(ctx)
if err != nil {
if isTransportError(err) { /* retry with backoff once or twice */ }
return fmt.Errorf("listing api keys: %w", err)
} Prevention
- Run 'headscale health' before scripted API-key operations
- Configure explicit timeouts in the CLI socket config
- Keep the CA cert for the server configured to avoid TLS transport failures
When it happens
Trigger: Running 'headscale apikeys list' when the gRPC-server is unreachable: wrong --address (default http://127.0.0.1:50443), server not running, TLS cert mismatch, or the CLI not pointed at the right socket.
Common situations: headscale serve/run not started or listening on a different address; httptest/CI environments where the server URL is not wired into the CLI config; self-signed certs without the CA configured; proxy environment variables (http_proxy) hijacking the connection.
Related errors
- creating api key: %w
- expiring api key: %w
- deleting api key: %w
- registering node: %w
- approving auth request: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/afec5d27673fcc77.
Report an issue: GitHub.