{"record":{"id":"5fd3bfb2a8586ef1","repo":"juanfont/headscale","slug":"action-q-is-not-supported-w","errorCode":null,"errorMessage":"action=%q is not supported: %w","messagePattern":"action=%q is not supported: %w","errorType":"validation","errorClass":"ErrInvalidACLAction","httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":1613,"sourceCode":"\nconst (\n\tSSHActionAccept SSHAction = \"accept\"\n\tSSHActionCheck  SSHAction = \"check\"\n)\n\n// String returns the string representation of the [Action].\nfunc (a *Action) String() string {\n\treturn string(*a)\n}\n\n// UnmarshalJSON implements JSON unmarshaling for [Action].\nfunc (a *Action) UnmarshalJSON(b []byte) error {\n\tstr := strings.Trim(string(b), `\"`)\n\tswitch str {\n\tcase \"accept\":\n\t\t*a = ActionAccept\n\tdefault:\n\t\treturn fmt.Errorf(\"action=%q is not supported: %w\", str, ErrInvalidACLAction)\n\t}\n\n\treturn nil\n}\n\n// MarshalJSON implements JSON marshaling for [Action].\nfunc (a *Action) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(string(*a))\n}\n\n// String returns the string representation of the [SSHAction].\nfunc (a *SSHAction) String() string {\n\treturn string(*a)\n}\n\n// UnmarshalJSON trims surrounding whitespace before matching, lets the\n// empty string through (per-rule Validate() surfaces it later), and\n// rejects every other unknown value here.","sourceCodeStart":1595,"sourceCodeEnd":1631,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L1595-L1631","documentation":"Action.UnmarshalJSON only accepts the literal \"accept\" for ACL rules. Any other action string is rejected with ErrInvalidACLAction.","triggerScenarios":"An ACL rule with \"action\": \"deny\" (or \"allow\", \"drop\", or a typo like \"Accept\") — deny semantics do not exist in this model, rules are allow-lists.","commonSituations":"Porting firewall-style configs that mix allow/deny rules; capitalization mismatches; outdated policy examples that predate the allow-list-only model.","solutions":["Remove deny rules entirely — express the complement by only listing what should be allowed","Use exactly \"accept\" (lowercase) for permitted rules"],"exampleFix":"// before\n{\"action\": \"deny\", \"src\": [...], \"dst\": [...]}\n// after\n// delete the deny rule; ensure allowed traffic is expressed as:\n{\"action\": \"accept\", \"src\": [...], \"dst\": [...]}","handlingStrategy":"validation","validationCode":"func validACLAction(s string) bool { return s == \"accept\" }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Remember ACLs are allow-lists: there is no deny action","Express exclusion by omission, not by deny rules"],"tags":["policy","acl","action","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}