gohugoio/hugo · error
version name is invalid
Error message
version name %q is invalid: %s
What it means
During versions config initialization, each version name key is validated with paths.ValidateIdentifier (versions.go:167-168), which requires the name to equal its normalized form — effectively all lowercase, no spaces, and no characters Hugo's path normalization would alter. A version name that fails (e.g. uppercase letters, spaces, or special characters) produces this error with the underlying reason.
Solutions
- Lowercase the version name and remove spaces (e.g. 'V1.0' -> 'v1.0', 'My Version' -> 'myversion').
- Use dots/dashes which ValidateIdentifier permits: 'v1.0.0', 'v1-0-0'.
- Keep version keys stable across content that references them (aliases/redirects) after renaming.
Example fix
// before (config) [versions] "V1.2.0" // after [versions] "v1.2.0"
Defensive patterns
Strategy: validation
Validate before calling
func normalizeVersionName(name string) (string, error) {
if name == "" {
return "", errors.New("version name cannot be empty")
}
norm := strings.ToLower(strings.ReplaceAll(name, " ", ""))
if err := paths.ValidateIdentifier(norm); err != nil {
return "", fmt.Errorf("version name %q is invalid: %w", name, err)
}
return norm, nil
} Type guard
func isValidVersionName(name string) bool {
return name != "" && name == paths.NormalizePathStringBasic(name)
} Prevention
- Use lowercase, space-free version keys (dots/dashes allowed).
- Add a config lint step that runs ValidateIdentifier on version keys.
- Keep version keys stable to avoid breaking content references.
When it happens
Trigger: Defining a [versions] config block with keys like 'V1.0', 'My Version', or 'v 1.0' — any key that is not already lowercase-alphanumeric-friendly triggers ValidateIdentifier failure ('must be all lower case and no spaces').
Common situations: Using SemVer-looking but uppercase version tags; copying version names from release notes that include spaces; renaming a version in config without normalizing.
Related errors
- config needs a filename
- invalid log level: , must be one of debug, warn, info or…
- language not found
- permalinks configuration invalid: unknown value
- permalinks configuration invalid: unknown value
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/ef7dc559a2018d53.
Report an issue: GitHub.
Appendix: source
Thrown at hugolib/versions/versions.go:168
if r.versionConfigs == nil {
r.versionConfigs = make(map[string]VersionConfig)
}
defaultContentVersionProvided := defaultContentVersion != ""
if len(r.versionConfigs) == 0 {
if defaultContentVersion == "" {
defaultContentVersion = defaultContentVersionFallback
}
// Add a default version.
r.versionConfigs[defaultContentVersion] = VersionConfig{}
}
var defaultSeen bool
for k, v := range r.versionConfigs {
if k == "" {
return errors.New("version name cannot be empty")
}
if err := paths.ValidateIdentifier(k); err != nil {
return fmt.Errorf("version name %q is invalid: %s", k, err)
}
var isDefault bool
if k == defaultContentVersion {
isDefault = true
defaultSeen = true
}
// Ignore error, this may not be a semver version.
parsedVersion, _ := version.ParseVersion(k)
r.Sorted = append(r.Sorted, VersionInternal{Name: k, parsedVersion: parsedVersion, Default: isDefault, VersionConfig: v})
}
// Sort by weight if set, then semver descending.
sort.SliceStable(r.Sorted, func(i, j int) bool {
ri, rj := r.Sorted[i], r.Sorted[j]
if ri.Weight == rj.Weight {View on GitHub (pinned to 52c9bd7908)