gohugoio/hugo · error

role name cannot be empty

Error message

role name cannot be empty

What it means

Thrown by RolesInternal.init in hugolib/roles/roles.go:150 when iterating the roleConfigs map and a key is the empty string. Hugo's content-roles feature (multi-audience rendering) keys each role by name, so an empty key is rejected before sorting/validation.

Solutions

  1. Inspect the [roles] section of hugo.toml and remove or rename any [roles.""] entry.
  2. Give every role a non-empty identifier, e.g. [roles.member] and [roles.admin].
  3. Run hugo config to print the resolved roles map and locate the empty key.

Example fix

// before
[roles]
[roles.""]
weight = 1
// after
[roles.member]
weight = 1
Defensive patterns

Strategy: validation

Validate before calling

// Before building config, reject empty role keys.
for k := range roleConfigs {
    if k == "" { return errors.New("remove empty role key") }
}

Prevention

When it happens

Trigger: Configuring [roles] with an empty-key sub-table in TOML (e.g. [roles.""]), or programmatically building a roles config map containing the "" key. The init runs during site matrix construction in site.go.

Common situations: Malformed TOML/YAML config under [roles], a copy-paste that produced an empty quoted key, or a config generator that emits a blank role entry. A default role ("guest") is added automatically when no roles are configured, so this only fires on an explicit empty key.

Related errors


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

Appendix: source

Thrown at hugolib/roles/roles.go:150

const defaultContentRoleFallback = "guest"

func (r *RolesInternal) init(defaultContentRole string) (string, error) {
	if r.roleConfigs == nil {
		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]

View on GitHub (pinned to 52c9bd7908)