{"record":{"id":"55610a7dc29e50a3","repo":"juanfont/headscale","slug":"w-local-part-must-be-got-q-in-q","errorCode":null,"errorMessage":"%w: local part must be *, got %q in %q","messagePattern":"%w: local part must be \\*, got %q in %q","errorType":"validation","errorClass":"ErrInvalidLocalpart","httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":3088,"sourceCode":"// Returns the domain part or an error if the format is invalid.\nfunc (u SSHUser) ParseLocalpart() (string, error) {\n\tif !u.IsLocalpart() {\n\t\treturn \"\", fmt.Errorf(\"%w: missing prefix %q in %q\", ErrInvalidLocalpart, SSHUserLocalpartPrefix, u)\n\t}\n\n\tpattern := strings.TrimPrefix(string(u), SSHUserLocalpartPrefix)\n\n\t// Must be *@<domain>\n\tatIdx := strings.LastIndex(pattern, \"@\")\n\tif atIdx < 0 {\n\t\treturn \"\", fmt.Errorf(\"%w: missing @ in %q\", ErrInvalidLocalpart, u)\n\t}\n\n\tlocalPart := pattern[:atIdx]\n\tdomain := pattern[atIdx+1:]\n\n\tif localPart != \"*\" {\n\t\treturn \"\", fmt.Errorf(\"%w: local part must be *, got %q in %q\", ErrInvalidLocalpart, localPart, u)\n\t}\n\n\tif domain == \"\" {\n\t\treturn \"\", fmt.Errorf(\"%w: empty domain in %q\", ErrInvalidLocalpart, u)\n\t}\n\n\treturn domain, nil\n}\n\n// MarshalJSON marshals the [SSHUser] to JSON.\nfunc (u SSHUser) MarshalJSON() ([]byte, error) {\n\treturn json.Marshal(string(u))\n}\n\n// UnmarshalJSON trims surrounding whitespace per element. A whitespace-\n// only entry collapses to `\"\"` and surfaces as `user \"\" is not valid` in\n// the per-rule [Policy.validate] pass.\nfunc (u *SSHUser) UnmarshalJSON(b []byte) error {","sourceCodeStart":3070,"sourceCodeEnd":3106,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L3070-L3106","documentation":"Error \"%w: local part must be *, got %q in %q\" thrown in juanfont/headscale.","triggerScenarios":"Thrown at hscontrol/policy/v2/types.go:3088 when the library encounters an invalid state.","commonSituations":"A localpart entry must be exactly '*@domain'. Replace the local part with '*' to match all users of the domain.","solutions":["Inspect the wrapped error for the underlying cause and correct the failing condition (); retry the operation after fixing the input, configuration, or environment."],"exampleFix":"Inspect the wrapped error for the underlying cause and correct the failing condition (); retry the operation after fixing the input, configuration, or environment.","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}