{"record":{"id":"afec5d27673fcc77","repo":"juanfont/headscale","slug":"listing-api-keys-w","errorCode":null,"errorMessage":"listing api keys: %w","messagePattern":"listing api keys: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/headscale/cli/api_key.go","lineNumber":50,"sourceCode":"\tdeleteAPIKeyCmd.Flags().StringP(\"prefix\", \"p\", \"\", \"ApiKey prefix\")\n\tdeleteAPIKeyCmd.Flags().Uint64P(\"id\", \"i\", 0, \"ApiKey ID\")\n\tapiKeysCmd.AddCommand(deleteAPIKeyCmd)\n}\n\nvar apiKeysCmd = &cobra.Command{\n\tUse:     \"apikeys\",\n\tShort:   \"Handle the Api keys in Headscale\",\n\tAliases: []string{\"apikey\", \"api\"},\n}\n\nvar listAPIKeys = &cobra.Command{\n\tUse:     cmdList,\n\tShort:   \"List the Api keys for headscale\",\n\tAliases: []string{\"ls\", cmdShow},\n\tRunE: clientRunE(func(ctx context.Context, client *clientv1.ClientWithResponses, cmd *cobra.Command, args []string) error {\n\t\tresp, err := client.ListApiKeysWithResponse(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"listing api keys: %w\", err)\n\t\t}\n\n\t\tif resp.StatusCode() != http.StatusOK {\n\t\t\treturn apiError(resp.StatusCode(), resp.ApplicationproblemJSONDefault)\n\t\t}\n\n\t\tapiKeys := resp.JSON200.ApiKeys\n\n\t\treturn printListOutput(cmd, apiKeys, func() error {\n\t\t\trows := make([][]string, 0, len(apiKeys))\n\t\t\tfor _, key := range apiKeys {\n\t\t\t\texpiration := \"-\"\n\t\t\t\tif key.Expiration != nil {\n\t\t\t\t\texpiration = ColourTime(*key.Expiration)\n\t\t\t\t}\n\n\t\t\t\tvar created string\n\t\t\t\tif key.CreatedAt != nil {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/api_key.go#L32-L68","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before listing, confirm the server endpoint answers\nreq, _ := http.NewRequest(http.MethodGet, addr+\"/health\", nil)\nif resp, err := http.DefaultClient.Do(req); err != nil || resp.StatusCode != 200 {\n\treturn fmt.Errorf(\"server not reachable at %s\", addr)\n}","typeGuard":"func isTransportError(err error) bool {\n\tvar netErr net.Error\n\treturn errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded)\n}","tryCatchPattern":"resp, err := client.ListApiKeysWithResponse(ctx)\nif err != nil {\n\tif isTransportError(err) { /* retry with backoff once or twice */ }\n\treturn fmt.Errorf(\"listing api keys: %w\", err)\n}","preventionTips":["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"],"tags":["network","http-client","cli","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}