{"record":{"id":"31eb40f8e15bc5f1","repo":"juanfont/headscale","slug":"expiring-api-key-w","errorCode":null,"errorMessage":"expiring api key: %w","messagePattern":"expiring api key: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/headscale/cli/api_key.go","lineNumber":153,"sourceCode":"\t\tid, prefix, err := apiKeyIDOrPrefix(cmd)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tbody := clientv1.ExpireApiKeyJSONRequestBody{}\n\n\t\tif id != 0 {\n\t\t\tidStr := strconv.FormatUint(id, util.Base10)\n\t\t\tbody.Id = &idStr\n\t\t}\n\n\t\tif prefix != \"\" {\n\t\t\tbody.Prefix = &prefix\n\t\t}\n\n\t\tresp, err := client.ExpireApiKeyWithResponse(ctx, body)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"expiring api key: %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\treturn printOutput(cmd, resp.JSON200, \"Key expired\")\n\t}),\n}\n\nvar deleteAPIKeyCmd = &cobra.Command{\n\tUse:     cmdDelete,\n\tShort:   \"Delete an ApiKey\",\n\tAliases: []string{\"remove\", aliasDel},\n\tRunE: clientRunE(func(ctx context.Context, client *clientv1.ClientWithResponses, cmd *cobra.Command, args []string) error {\n\t\tid, prefix, err := apiKeyIDOrPrefix(cmd)\n\t\tif err != nil {\n\t\t\treturn err","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/api_key.go#L135-L171","documentation":"Transport-level failure of 'headscale apikeys expire': client.ExpireApiKeyWithResponse returned an error before an HTTP response was received. Covers connection failures, TLS errors, and request serialization/timeout problems, not server-side rejections (those come back as non-200 and are surfaced through apiError).","triggerScenarios":"Expiring a key while the server is down, restarting, or unreachable; context cancelled (Ctrl-C or --timeout); TLS trust misconfigured between CLI and server.","commonSituations":"Server restart window during automation; wrong --address in scripted environments; expired certificates on the control server.","solutions":["Check server status with 'headscale health' and retry once it is up","Validate CLI address and CA settings against the server configuration","If it recurs, capture the wrapped error text — 'connection refused' vs 'context deadline exceeded' distinguishes config from timeout"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := client.ExpireApiKeyWithResponse(ctx, body); err != nil {\n\tif isTransportError(err) { retryAfterBackoff() } else { return err }\n}","preventionTips":["Expire is safe to re-run: a transport-failed expire can be retried after checking 'apikeys list'","Avoid expiring keys during planned server restarts"],"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"}