{"record":{"id":"fc1a65f660b4f3a0","repo":"juanfont/headscale","slug":"w-group-q-got-t","errorCode":null,"errorMessage":"%w: group %q got %T","messagePattern":"%w: group %q got %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":1354,"sourceCode":"\tfor key, value := range rawMap {\n\t\tswitch v := value.(type) {\n\t\tcase []any:\n\t\t\t// Convert []interface{} to []string\n\t\t\tvar stringSlice []string\n\n\t\t\tfor _, item := range v {\n\t\t\t\tif str, ok := item.(string); ok {\n\t\t\t\t\tstringSlice = append(stringSlice, str)\n\t\t\t\t} else {\n\t\t\t\t\treturn fmt.Errorf(\"%w: group %q expected string but got %T\", ErrInvalidGroupMember, key, item)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\trawGroups[key] = stringSlice\n\t\tcase string:\n\t\t\treturn fmt.Errorf(\"%w: group %q got string: %q\", ErrGroupValueNotArray, key, v)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"%w: group %q got %T\", ErrGroupValueNotArray, key, v)\n\t\t}\n\t}\n\n\t// Reject group-in-group references. Reverse-sort the keys so the\n\t// reported (parent, child) pair names the deepest non-leaf parent\n\t// first.\n\tkeys := make([]string, 0, len(rawGroups))\n\tfor k := range rawGroups {\n\t\tkeys = append(keys, k)\n\t}\n\n\tslices.Sort(keys)\n\tslices.Reverse(keys)\n\n\tfor _, key := range keys {\n\t\tfor _, u := range rawGroups[key] {\n\t\t\tif isGroup(u) {\n\t\t\t\treturn fmt.Errorf(\"groups[%q]: %q: %w\", key, u, ErrGroupMembersCannotBeRecursive)","sourceCodeStart":1336,"sourceCodeEnd":1372,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L1336-L1372","documentation":"A groups entry's value is neither an array nor a string — it is a number, object, boolean, or null (ErrGroupValueNotArray). The message reports the Go type seen.","triggerScenarios":"Writing \"group:x\": 5, {\"group:x\": {}}, or \"group:x\": null in the groups map.","commonSituations":"Programmatic policy generation with wrong types, or commented-out values collapsing to null in JSON.","solutions":["Make every groups value an array of username strings","Delete null placeholder entries entirely"],"exampleFix":"// before\n{\"group:eng\": null}\n// after\n{\"group:eng\": [\"dev@example.com\"]}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func groupValueShapeOk(v any) bool {\n\tswitch v.(type) {\n\tcase []any, string: return true\n\tdefault: return false\n\t}\n}","tryCatchPattern":null,"preventionTips":["Never emit null or numeric group values from generators","Delete placeholder group entries instead of nulling them"],"tags":["policy","groups","json","type-error"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}