juanfont/headscale · error · ErrSSHTestEmptySrc
SSH tests entry must have a non-empty src
Error message
SSH tests entry must have a non-empty src
What it means
ErrSSHTestEmptySrc is returned by validateSSHTests (hscontrol/policy/v2/types.go:3283) when an sshTests entry has no usable "src" (nil Alias). Every SSH test must name who is attempting the connection. The src field unmarshals into an *Alias so a whitespace-only or missing value surfaces here rather than as a parser error (see test.go:103).
Source
Thrown at hscontrol/policy/v2/types.go:152
ErrAutogroupNotSupported = errors.New("autogroup not supported in headscale")
ErrAutogroupInternetSrc = errors.New("autogroup:internet can only be used in ACL destinations")
ErrAutogroupSelfSrc = errors.New("\"autogroup:self\" not valid on the src side of a rule")
ErrAutogroupNotSupportedACLSrc = errors.New("autogroup not supported for ACL sources")
ErrAutogroupNotSupportedACLDst = errors.New("autogroup not supported for ACL destinations")
ErrAutogroupDangerAllDst = errors.New("cannot use autogroup:danger-all as a dst")
ErrAutogroupNotSupportedSSHSrc = errors.New("autogroup not supported for SSH sources")
ErrAutogroupNotSupportedSSHDst = errors.New("autogroup not supported for SSH destinations")
ErrHostNotDefined = errors.New("host not defined in policy")
ErrSSHSourceAliasNotSupported = errors.New("alias not supported for SSH source")
ErrSSHDestAliasNotSupported = errors.New("alias not supported for SSH destination")
ErrUnknownField = errors.New("unknown field")
ErrProtocolNoSpecificPorts = errors.New("protocol does not support specific ports")
ErrTestEmptyAssertions = errors.New("test entry must have at least one of \"accept\" or \"deny\"")
ErrTestProtocolNotAllowed = errors.New("test protocol must be tcp, udp, sctp, or empty")
ErrTestDestinationMultiPort = errors.New("test destination port must be a single port")
ErrTestDestinationCIDR = errors.New("test destination must be a single host, not a CIDR range")
ErrAutogroupInternetTestDst = errors.New("autogroup:internet not valid as a test destination")
ErrSSHTestEmptySrc = errors.New("SSH tests entry must have a non-empty src")
ErrSSHTestEmptyDst = errors.New("SSH tests entry must have at least one dst")
ErrSSHTestDstUnknownTag = errors.New("SSH tests dst contains unknown tag")
ErrSSHTestDstDisallowedElement = errors.New("SSH tests dst contains disallowed element")
)
type resolved struct {
ips netipx.IPSet
}
func newResolved(ipb *netipx.IPSetBuilder) (resolved, error) {
ips, err := ipb.IPSet()
if err != nil {
return resolved{}, err
}
return resolved{ips: *ips}, nil
}
View on GitHub (pinned to 565fd254d0)
Solutions
- Add a src to the flagged sshTests entry — a user (user:*, user:name), group, tag, or autogroup valid for SSH sources
- If the entry was scaffolding, delete it
- Re-validate; remaining sshTests shape errors (empty dst, bad dst) are reported together
Example fix
// before
"sshTests": [{"dst": ["tag:server"], "accept": ["root"]}]
// after
"sshTests": [{"src": "group:admin", "dst": ["tag:server"], "accept": ["root"]}] Defensive patterns
Strategy: validation
Validate before calling
// Before marshalling a policy, ensure every sshTests entry has src set
func sshTestEntriesValid(tests []SSHPolicyTest) bool {
for _, t := range tests {
if t.Src == nil { return false }
}
return true
} Try / catch
if errors.Is(err, policyv2.ErrSSHTestEmptySrc) {
// add a user/group/tag/autogroup src to the flagged entry (index in message)
} Prevention
- sshTests entries always need both src and dst
- Do not commit scaffolding entries
- Remember whitespace-only src collapses to nil and hits this same error
When it happens
Trigger: An sshTests entry like {"dst": ["tag:server"], "accept": ["root"]} with src omitted, or src set to an empty string that collapses to nil. Raised when t.Src == nil during policy validation.
Common situations: Scaffolding an ssh test and forgetting the user side; trimming/copy-paste dropping the src line; assuming src is optional like proto in packet tests (it is not).
Related errors
- SSH tests entry must have at least one dst
- SSH tests dst contains unknown tag
- tags in SSH source cannot access user-owned devices
- user destination requires source to contain only that same u
- autogroup:self destination requires source to contain only u
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/8845996dcfd36911.
Report an issue: GitHub.