{"record":{"id":"d90d09147aa0d0f6","repo":"juanfont/headscale","slug":"either-id-or-prefix-must-be-provided-w","errorCode":null,"errorMessage":"either --id or --prefix must be provided: %w","messagePattern":"either --id or --prefix must be provided: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"cmd/headscale/cli/api_key.go","lineNumber":122,"sourceCode":"\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.ApiKey, resp.JSON200.ApiKey)\n\t}),\n}\n\n// apiKeyIDOrPrefix reads --id and --prefix from cmd and validates that\n// exactly one is provided.\nfunc apiKeyIDOrPrefix(cmd *cobra.Command) (uint64, string, error) {\n\tid, _ := cmd.Flags().GetUint64(\"id\")\n\tprefix, _ := cmd.Flags().GetString(\"prefix\")\n\n\tswitch {\n\tcase id == 0 && prefix == \"\":\n\t\treturn 0, \"\", fmt.Errorf(\"either --id or --prefix must be provided: %w\", errMissingParameter)\n\tcase id != 0 && prefix != \"\":\n\t\treturn 0, \"\", fmt.Errorf(\"only one of --id or --prefix can be provided: %w\", errMissingParameter)\n\t}\n\n\treturn id, prefix, nil\n}\n\nvar expireAPIKeyCmd = &cobra.Command{\n\tUse:     cmdExpire,\n\tShort:   \"Expire an ApiKey\",\n\tAliases: []string{\"revoke\", aliasExp, \"e\"},\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\n\t\t}\n\n\t\tbody := clientv1.ExpireApiKeyJSONRequestBody{}","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/api_key.go#L104-L140","documentation":"Validation error from apiKeyIDOrPrefix: the user invoked an API-key subcommand (expire/delete) with neither --id nor --prefix. At least one identifier is required because the server routes the request to a specific key. It wraps the sentinel errMissingParameter so callers can test for it with errors.Is.","triggerScenarios":"Running 'headscale apikeys expire' or 'headscale apikeys delete' with no --id and no --prefix flags (id==0 and prefix==\"\").","commonSituations":"Scripts written for an older CLI that took a positional key argument; users assuming the command operates on the most recent key; typos in flag names so both flags read as unset.","solutions":["Pass exactly one of --id <n> or --prefix <prefix>","Find valid values first with 'headscale apikeys list'","For scripts, capture the id/prefix from the create or list output programmatically"],"exampleFix":"# before\nheadscale apikeys expire\n\n# after\nheadscale apikeys expire --prefix abcdef1234","handlingStrategy":"validation","validationCode":"id, _ := cmd.Flags().GetUint64(\"id\")\nprefix, _ := cmd.Flags().GetString(\"prefix\")\nif id == 0 && prefix == \"\" {\n\treturn fmt.Errorf(\"pass --id or --prefix; see 'headscale apikeys list'\")\n}","typeGuard":null,"tryCatchPattern":"if err := cmd.Execute(); err != nil {\n\tif errors.Is(err, cli.ErrMissingParameter) { /* print usage hint and exit 2 */ }\n}","preventionTips":["Default scripts to --prefix captured at creation time","Validate flags before invoking the CLI in shell scripts (set -u + explicit arg checks)"],"tags":["cli","validation","flags","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}