juanfont/headscale · error
invalid group member type
Error message
invalid group member type
What it means
Group member parsing (hscontrol/policy/v2/types.go:1346) requires every item in a group's member array to be a JSON string. A non-string element (number, object, nested array) yields this sentinel with the group key and the element's Go %T. Note the sibling ErrGroupValueNotArray covers the whole value not being an array at all.
Source
Thrown at hscontrol/policy/v2/types.go:124
// Policy validation errors.
var (
ErrInvalidUsername = errors.New("username must contain @")
ErrUserNotFound = errors.New("user not found")
ErrMultipleUsersFound = errors.New("multiple users found")
ErrInvalidGroupFormat = errors.New("group must start with 'group:'")
ErrInvalidTagFormat = errors.New("tag must start with 'tag:'")
ErrInvalidHostname = errors.New("invalid hostname")
ErrHostResolve = errors.New("error resolving host")
ErrInvalidPrefix = errors.New("invalid prefix")
ErrInvalidAutogroup = errors.New("invalid autogroup")
ErrUnknownAutogroup = errors.New("unknown autogroup")
ErrHostportMissingColon = errors.New("hostport must contain a colon")
ErrTypeNotSupported = errors.New("type not supported")
ErrInvalidAlias = errors.New("invalid alias format")
ErrInvalidAutoApprover = errors.New("invalid auto approver format")
ErrInvalidOwner = errors.New("invalid owner format")
ErrGroupNotDefined = errors.New("group not defined in policy")
ErrInvalidGroupMember = errors.New("invalid group member type")
ErrGroupValueNotArray = errors.New("group value must be an array of users")
ErrInvalidHostIP = errors.New("hostname contains invalid IP address")
ErrTagNotDefined = errors.New("tag not found")
ErrAutoApproverNotAlias = errors.New("auto approver is not an alias")
ErrInvalidACLAction = errors.New("invalid ACL action")
ErrInvalidSSHAction = errors.New("invalid SSH action")
ErrInvalidProtocolNumber = errors.New("invalid protocol number")
ErrProtocolLeadingZero = errors.New("leading 0 not permitted in protocol number")
ErrProtocolOutOfRange = errors.New("protocol number out of range (0-255)")
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")View on GitHub (pinned to 565fd254d0)
Solutions
- Make every group member a plain string username/email
- Fix the generator to serialize all members as strings
- Lint generated policy JSON before applying
Example fix
// before
{"groups": {"group:admins": ["alice@", 7]}}
// after
{"groups": {"group:admins": ["alice@", "bob@"]}} Defensive patterns
Strategy: type-guard
Validate before calling
for _, g := range rawGroups {
for _, m := range g {
if _, ok := m.(string); !ok {
return fmt.Errorf("group member must be string, got %T", m)
}
}
} Type guard
func isStringMember(v any) bool { _, ok := v.(string); return ok } Try / catch
if errors.Is(err, policy.ErrInvalidGroupMember) {
// %T names the bad element; make every member a quoted string
} Prevention
- Serialize group members as JSON strings only
- Validate generated arrays element-wise before applying
When it happens
Trigger: {"groups": {"group:admins": ["alice@", 42]}} or a member rendered as {"user": "alice"} by a template/code generator. Fails while unmarshalling the groups map.
Common situations: Programmatic policy generation emitting mixed-type arrays; YAML-to-JSON conversion turning a scalar into a non-string; hand-editing adding a numeric user ID or comment object inside the member list.
Related errors
- group value must be an array of users
- group must start with 'group:'
- test(s) failed
- tags in SSH source cannot access user-owned devices
- user destination requires source to contain only that same u
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/85cb1ab70e5e7eb1.
Report an issue: GitHub.