gohugoio/hugo · error

role name is invalid

Error message

role name %q is invalid: %s

What it means

Raised by RolesInternal.init (roles.go:154) when a configured role name fails paths.ValidateIdentifier, which requires the string to equal its NormalizePathStringBasic form — i.e. all lowercase ASCII, no spaces, no slashes, no punctuation outside the basic path character set.

Solutions

  1. Use lowercase, hyphen-separated, space-free role identifiers in config (e.g. `editor`, `guest`, `en-us`).
  2. If you need a display name, store it separately and keep the key as a slug.

Example fix

# before (hugo.toml)
[roles]
  [roles."Editor Role"]
    weight = 1

# after
[roles]
  [roles.editor]
    weight = 1
Defensive patterns

Strategy: validation

Validate before calling

# Validate every role key is lowercase, no spaces.
awk '/^\[roles\./ { 
  name=$0; gsub(/\[roles\.|\]/,"",name); 
  if (name != tolower(name) || name ~ / /) print "bad role: " name
}' hugo.toml

Prevention

When it happens

Trigger: Declaring a role under `roles` in config with uppercase letters, spaces, or special characters (e.g. `Editor Role`, `Editor`, `en-US`). The validator runs on every role-config key during init.

Common situations: Defining content roles for a multi-role Hugo setup using friendly display names instead of slugs; copy-pasting role names from a UI label field; locale-style names with hyphens or uppercase region codes.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/ae584f36bc2802db. Report an issue: GitHub.

Appendix: source

Thrown at hugolib/roles/roles.go:154

		r.roleConfigs = make(map[string]RoleConfig)
	}
	defaultContentRoleProvided := defaultContentRole != ""
	if len(r.roleConfigs) == 0 {
		// Add a default role.
		if defaultContentRole == "" {
			defaultContentRole = defaultContentRoleFallback
		}
		r.roleConfigs[defaultContentRole] = RoleConfig{}
	}

	var defaultSeen bool
	for k, v := range r.roleConfigs {
		if k == "" {
			return "", errors.New("role name cannot be empty")
		}

		if err := paths.ValidateIdentifier(k); err != nil {
			return "", fmt.Errorf("role name %q is invalid: %s", k, err)
		}

		var isDefault bool
		if k == defaultContentRole {
			isDefault = true
			defaultSeen = true
		}

		r.Sorted = append(r.Sorted, RoleInternal{Name: k, Default: isDefault, RoleConfig: v})
	}

	// Sort by weight if set, then by name.
	sort.SliceStable(r.Sorted, func(i, j int) bool {
		ri, rj := r.Sorted[i], r.Sorted[j]
		if ri.Weight == rj.Weight {
			return ri.Name < rj.Name
		}
		if rj.Weight == 0 {

View on GitHub (pinned to 52c9bd7908)