{"id":"ef7dc559a2018d53","repo":"gohugoio/hugo","slug":"version-name-q-is-invalid-s","errorCode":null,"errorMessage":"version name %q is invalid: %s","messagePattern":"version name %q is invalid: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hugolib/versions/versions.go","lineNumber":168,"sourceCode":"\tif r.versionConfigs == nil {\n\t\tr.versionConfigs = make(map[string]VersionConfig)\n\t}\n\tdefaultContentVersionProvided := defaultContentVersion != \"\"\n\tif len(r.versionConfigs) == 0 {\n\t\tif defaultContentVersion == \"\" {\n\t\t\tdefaultContentVersion = defaultContentVersionFallback\n\t\t}\n\t\t// Add a default version.\n\t\tr.versionConfigs[defaultContentVersion] = VersionConfig{}\n\t}\n\n\tvar defaultSeen bool\n\tfor k, v := range r.versionConfigs {\n\t\tif k == \"\" {\n\t\t\treturn errors.New(\"version name cannot be empty\")\n\t\t}\n\t\tif err := paths.ValidateIdentifier(k); err != nil {\n\t\t\treturn fmt.Errorf(\"version name %q is invalid: %s\", k, err)\n\t\t}\n\n\t\tvar isDefault bool\n\t\tif k == defaultContentVersion {\n\t\t\tisDefault = true\n\t\t\tdefaultSeen = true\n\t\t}\n\n\t\t// Ignore error, this may not be a semver version.\n\t\tparsedVersion, _ := version.ParseVersion(k)\n\n\t\tr.Sorted = append(r.Sorted, VersionInternal{Name: k, parsedVersion: parsedVersion, Default: isDefault, VersionConfig: v})\n\t}\n\n\t// Sort by weight if set, then semver descending.\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 {","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/gohugoio/hugo/blob/8a468df065a75c1c7cf9f6850f32148746590ea5/hugolib/versions/versions.go#L150-L186","documentation":"Raised right after the empty-name check (hugolib/versions/versions.go:168) when a version name fails paths.ValidateIdentifier. Version names are used as path segments/identifiers, so they must be valid identifiers; the wrapped %s explains which rule was violated.","triggerScenarios":"A versions config key containing characters rejected by paths.ValidateIdentifier — e.g. spaces, slashes, uppercase-or-symbol combinations disallowed for Hugo identifiers (like \"v 1.0\" or \"v1/beta\").","commonSituations":"Naming versions after human-readable release titles (\"Release 2024\"), including slashes to imply nesting, or copying git tag names with characters invalid as path identifiers.","solutions":["Rename the version to a plain identifier: lowercase letters, digits, dots, hyphens (e.g. v1.2.0).","Read the appended validation message for the exact offending character and remove it.","If you want a display title, keep the key simple and set a title inside that version's config."],"exampleFix":"# before\nversions:\n  \"v 1.0/beta\": {}\n# after\nversions:\n  v1.0-beta: {}","handlingStrategy":"validation","validationCode":"var validVersion = regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)\nfor _, v := range versionsConfig {\n    if !validVersion.MatchString(v.Name) {\n        return fmt.Errorf(\"invalid version name %q\", v.Name)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Restrict version names to safe path-friendly characters (alphanumerics, dot, dash, underscore)","Avoid spaces, slashes, and special characters in version names since they become URL/path segments","Validate any user-supplied or generated version names against the same rule Hugo enforces before writing config"],"tags":["hugo","config","versions","validation"],"analyzedSha":"8a468df065a75c1c7cf9f6850f32148746590ea5","analyzedAt":"2026-07-31T21:23:07.045Z","schemaVersion":2}