{"record":{"id":"85cb1ab70e5e7eb1","repo":"juanfont/headscale","slug":"invalid-group-member-type","errorCode":null,"errorMessage":"invalid group member type","messagePattern":"invalid group member type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":124,"sourceCode":"// Policy validation errors.\nvar (\n\tErrInvalidUsername             = errors.New(\"username must contain @\")\n\tErrUserNotFound                = errors.New(\"user not found\")\n\tErrMultipleUsersFound          = errors.New(\"multiple users found\")\n\tErrInvalidGroupFormat          = errors.New(\"group must start with 'group:'\")\n\tErrInvalidTagFormat            = errors.New(\"tag must start with 'tag:'\")\n\tErrInvalidHostname             = errors.New(\"invalid hostname\")\n\tErrHostResolve                 = errors.New(\"error resolving host\")\n\tErrInvalidPrefix               = errors.New(\"invalid prefix\")\n\tErrInvalidAutogroup            = errors.New(\"invalid autogroup\")\n\tErrUnknownAutogroup            = errors.New(\"unknown autogroup\")\n\tErrHostportMissingColon        = errors.New(\"hostport must contain a colon\")\n\tErrTypeNotSupported            = errors.New(\"type not supported\")\n\tErrInvalidAlias                = errors.New(\"invalid alias format\")\n\tErrInvalidAutoApprover         = errors.New(\"invalid auto approver format\")\n\tErrInvalidOwner                = errors.New(\"invalid owner format\")\n\tErrGroupNotDefined             = errors.New(\"group not defined in policy\")\n\tErrInvalidGroupMember          = errors.New(\"invalid group member type\")\n\tErrGroupValueNotArray          = errors.New(\"group value must be an array of users\")\n\tErrInvalidHostIP               = errors.New(\"hostname contains invalid IP address\")\n\tErrTagNotDefined               = errors.New(\"tag not found\")\n\tErrAutoApproverNotAlias        = errors.New(\"auto approver is not an alias\")\n\tErrInvalidACLAction            = errors.New(\"invalid ACL action\")\n\tErrInvalidSSHAction            = errors.New(\"invalid SSH action\")\n\tErrInvalidProtocolNumber       = errors.New(\"invalid protocol number\")\n\tErrProtocolLeadingZero         = errors.New(\"leading 0 not permitted in protocol number\")\n\tErrProtocolOutOfRange          = errors.New(\"protocol number out of range (0-255)\")\n\tErrAutogroupNotSupported       = errors.New(\"autogroup not supported in headscale\")\n\tErrAutogroupInternetSrc        = errors.New(\"autogroup:internet can only be used in ACL destinations\")\n\tErrAutogroupSelfSrc            = errors.New(\"\\\"autogroup:self\\\" not valid on the src side of a rule\")\n\tErrAutogroupNotSupportedACLSrc = errors.New(\"autogroup not supported for ACL sources\")\n\tErrAutogroupNotSupportedACLDst = errors.New(\"autogroup not supported for ACL destinations\")\n\tErrAutogroupDangerAllDst       = errors.New(\"cannot use autogroup:danger-all as a dst\")\n\tErrAutogroupNotSupportedSSHSrc = errors.New(\"autogroup not supported for SSH sources\")\n\tErrAutogroupNotSupportedSSHDst = errors.New(\"autogroup not supported for SSH destinations\")\n\tErrHostNotDefined              = errors.New(\"host not defined in policy\")","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L106-L142","documentation":"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.","triggerScenarios":"{\"groups\": {\"group:admins\": [\"alice@\", 42]}} or a member rendered as {\"user\": \"alice\"} by a template/code generator. Fails while unmarshalling the groups map.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"groups\": {\"group:admins\": [\"alice@\", 7]}}\n// after\n{\"groups\": {\"group:admins\": [\"alice@\", \"bob@\"]}}","handlingStrategy":"type-guard","validationCode":"for _, g := range rawGroups {\n    for _, m := range g {\n        if _, ok := m.(string); !ok {\n            return fmt.Errorf(\"group member must be string, got %T\", m)\n        }\n    }\n}","typeGuard":"func isStringMember(v any) bool { _, ok := v.(string); return ok }","tryCatchPattern":"if errors.Is(err, policy.ErrInvalidGroupMember) {\n    // %T names the bad element; make every member a quoted string\n}","preventionTips":["Serialize group members as JSON strings only","Validate generated arrays element-wise before applying"],"tags":["headscale","policy","groups","json","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}