{"record":{"id":"26b0033ccfd8572c","repo":"juanfont/headscale","slug":"w-api-key-d-not-found","errorCode":null,"errorMessage":"%w: api key %d not found","messagePattern":"%w: api key (.+?) not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/headscale/cli/api_key.go","lineNumber":222,"sourceCode":"\tid uint64,\n) (string, error) {\n\tresp, err := client.ListApiKeysWithResponse(ctx)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"listing api keys: %w\", err)\n\t}\n\n\tif resp.StatusCode() != http.StatusOK {\n\t\treturn \"\", apiError(resp.StatusCode(), resp.ApplicationproblemJSONDefault)\n\t}\n\n\tidStr := strconv.FormatUint(id, util.Base10)\n\tfor _, key := range resp.JSON200.ApiKeys {\n\t\tif key.Id == idStr {\n\t\t\treturn key.Prefix, nil\n\t\t}\n\t}\n\n\treturn \"\", fmt.Errorf(\"%w: api key %d not found\", errMissingParameter, id)\n}\n","sourceCodeStart":204,"sourceCodeEnd":224,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/api_key.go#L204-L224","documentation":"Returned by apiKeyPrefixForID when 'headscale apikeys delete --id N' cannot find any key whose Id matches N in the ListApiKeys response — the prefix resolution needed for the DELETE path failed. Wraps errMissingParameter, so errors.Is(err, errMissingParameter) is true.","triggerScenarios":"Deleting by an --id that does not exist: already-deleted key, id from a different server/database, or a typo. The list call succeeds but no entry matches the formatted id string.","commonSituations":"Key was expired and pruned between listing and deleting; scripts reusing stale ids after a DB reset; confusing the key id with the node or user id.","solutions":["Run 'headscale apikeys list' and copy the current id or prefix","If the key is already gone, the goal is achieved — treat as success in scripts","Prefer --prefix in automation since it addresses the key directly without the list/resolve step"],"exampleFix":"# before\nheadscale apikeys delete --id 42\n\n# after\nheadscale apikeys list\nheadscale apikeys delete --prefix $(headscale apikeys list -o json | jq -r '.apiKeys[0].prefix')","handlingStrategy":"validation","validationCode":"// verify the id exists before attempting delete-by-id\nkeys, err := listAPIKeys(ctx, client)\nif err != nil { return err }\nfound := slices.ContainsFunc(keys, func(k ApiKey) bool { return k.Id == idStr })\nif !found { return nil /* already gone: treat as success */ }","typeGuard":null,"tryCatchPattern":"if err := deleteKey(ctx, client, id); err != nil {\n\tif strings.Contains(err.Error(), \"not found\") { return nil }\n\treturn err\n}","preventionTips":["Treat 'not found' on delete as idempotent success in automation","Refresh ids from 'apikeys list' at the start of each script run","Prefer prefix addressing in scripts"],"tags":["cli","not-found","validation","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}