juanfont/headscale · error · ErrSSHActionInvalid

%q %w

Error message

%q %w

What it means

SSHAction.UnmarshalJSON accepts "accept", "check", or an empty string (surfaced later by per-rule Validate). Anything else returns ErrSSHActionInvalid with the value.

Source

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

// 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.
func (a *SSHAction) UnmarshalJSON(b []byte) error {
	str := strings.TrimSpace(strings.Trim(string(b), `"`))
	switch str {
	case "":
		*a = SSHAction("")
	case "accept":
		*a = SSHActionAccept
	case "check":
		*a = SSHActionCheck
	default:
		return fmt.Errorf("%q %w", str, ErrSSHActionInvalid)
	}

	return nil
}

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

// Protocol represents a network protocol with its IANA number and descriptions.
type Protocol string

const (
	ProtocolNameICMP     Protocol = "icmp"
	ProtocolNameIGMP     Protocol = "igmp"
	ProtocolNameIPv4     Protocol = "ipv4"
	ProtocolNameIPInIP   Protocol = "ip-in-ip"

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use "accept" or "check" as the ssh action
  2. Delete rules intended as denies — absence of a rule already denies SSH
  3. Check spelling and quoting of the action string

Example fix

// before
{"action": "deny", "src": [...], "dst": [...], "users": [...]}
// after
{"action": "check", "src": [...], "dst": [...], "users": [...]}
Defensive patterns

Strategy: validation

Validate before calling

func validSSHAction(s string) bool {
	switch s { case "", "accept", "check": return true }
	return false
}

Prevention

When it happens

Trigger: An ssh rule with "action": "deny" or a typo like "accep" — SSH rules cannot deny, they only grant accept or check-session modes.

Common situations: Writing deny-style SSH rules; copy-paste from ACL actions assuming the same vocabulary; trailing whitespace variants other than simple trim cases.

Related errors


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