juanfont/headscale · error · ErrInvalidACLAction

action=%q is not supported: %w

Error message

action=%q is not supported: %w

What it means

Action.UnmarshalJSON only accepts the literal "accept" for ACL rules. Any other action string is rejected with ErrInvalidACLAction.

Source

Thrown at hscontrol/policy/v2/types.go:1613

const (
	SSHActionAccept SSHAction = "accept"
	SSHActionCheck  SSHAction = "check"
)

// String returns the string representation of the [Action].
func (a *Action) String() string {
	return string(*a)
}

// UnmarshalJSON implements JSON unmarshaling for [Action].
func (a *Action) UnmarshalJSON(b []byte) error {
	str := strings.Trim(string(b), `"`)
	switch str {
	case "accept":
		*a = ActionAccept
	default:
		return fmt.Errorf("action=%q is not supported: %w", str, ErrInvalidACLAction)
	}

	return nil
}

// MarshalJSON implements JSON marshaling for [Action].
func (a *Action) MarshalJSON() ([]byte, error) {
	return json.Marshal(string(*a))
}

// String returns the string representation of the [SSHAction].
func (a *SSHAction) String() string {
	return string(*a)
}

// UnmarshalJSON trims surrounding whitespace before matching, lets the
// empty string through (per-rule Validate() surfaces it later), and
// rejects every other unknown value here.

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Remove deny rules entirely — express the complement by only listing what should be allowed
  2. Use exactly "accept" (lowercase) for permitted rules

Example fix

// before
{"action": "deny", "src": [...], "dst": [...]}
// after
// delete the deny rule; ensure allowed traffic is expressed as:
{"action": "accept", "src": [...], "dst": [...]}
Defensive patterns

Strategy: validation

Validate before calling

func validACLAction(s string) bool { return s == "accept" }

Prevention

When it happens

Trigger: 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.

Common situations: Porting firewall-style configs that mix allow/deny rules; capitalization mismatches; outdated policy examples that predate the allow-list-only model.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/5fd3bfb2a8586ef1. Report an issue: GitHub.