{"id":"ae584f36bc2802db","repo":"gohugoio/hugo","slug":"role-name-q-is-invalid-s","errorCode":null,"errorMessage":"role name %q is invalid: %s","messagePattern":"role name %q is invalid: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hugolib/roles/roles.go","lineNumber":154,"sourceCode":"\t\tr.roleConfigs = make(map[string]RoleConfig)\n\t}\n\tdefaultContentRoleProvided := defaultContentRole != \"\"\n\tif len(r.roleConfigs) == 0 {\n\t\t// Add a default role.\n\t\tif defaultContentRole == \"\" {\n\t\t\tdefaultContentRole = defaultContentRoleFallback\n\t\t}\n\t\tr.roleConfigs[defaultContentRole] = RoleConfig{}\n\t}\n\n\tvar defaultSeen bool\n\tfor k, v := range r.roleConfigs {\n\t\tif k == \"\" {\n\t\t\treturn \"\", errors.New(\"role name cannot be empty\")\n\t\t}\n\n\t\tif err := paths.ValidateIdentifier(k); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"role name %q is invalid: %s\", k, err)\n\t\t}\n\n\t\tvar isDefault bool\n\t\tif k == defaultContentRole {\n\t\t\tisDefault = true\n\t\t\tdefaultSeen = true\n\t\t}\n\n\t\tr.Sorted = append(r.Sorted, RoleInternal{Name: k, Default: isDefault, RoleConfig: v})\n\t}\n\n\t// Sort by weight if set, then by name.\n\tsort.SliceStable(r.Sorted, func(i, j int) bool {\n\t\tri, rj := r.Sorted[i], r.Sorted[j]\n\t\tif ri.Weight == rj.Weight {\n\t\t\treturn ri.Name < rj.Name\n\t\t}\n\t\tif rj.Weight == 0 {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/hugolib/roles/roles.go#L136-L172","documentation":"Raised when a configured role name fails `paths.ValidateIdentifier` during roles-registry construction. Role names are used as path/identifier components in Hugo, so they must conform to Hugo's identifier rules (letters, digits, and a limited set of separators — no spaces or exotic characters). The wrapped `%s` gives the specific validation failure.","triggerScenarios":"A `roles` config entry keyed with characters that `paths.ValidateIdentifier` rejects, e.g. `roles: { 'my role!': {} }` or names containing slashes, spaces, or uppercase/unicode characters the validator disallows.","commonSituations":"Using human-readable display names (\"Site Admin\") as the role key instead of a slug; migrating role definitions from another system that allows spaces; punctuation typos in config keys.","solutions":["Rename the role key to a simple identifier (lowercase letters, digits, hyphens) and read the wrapped message for the exact rule violated.","If you need a display name, keep the key as a slug and put the friendly name in the role's config fields.","Re-run `hugo` after fixing; the error names the offending key with %q so it's directly searchable in your config."],"exampleFix":"# before\nroles:\n  \"Site Admin!\": {}\n\n# after\nroles:\n  site-admin: {}","handlingStrategy":"validation","validationCode":"var validRole = regexp.MustCompile(`^[a-z][a-z0-9_-]*$`)\nif !validRole.MatchString(name) {\n    return fmt.Errorf(\"invalid role name %q\", name)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    // surface the embedded reason (%s) to the user; do not retry with the same name\n}","preventionTips":["Restrict role names to lowercase alphanumerics plus - and _","Validate role names where they are authored (config schema / lint step) rather than at build time","Reuse one shared validation function so every entry point applies the same rules"],"tags":["hugo","config","roles","validation"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}