gohugoio/hugo · error
cannot create " ": Windows filename restriction
Error message
cannot create "%s": Windows filename restriction
What it means
Returned by targetPathAlias only on Windows (runtime.GOOS == "windows") when the alias fails one or more Windows filename checks: reserved device names (CON, PRN, AUX, NUL, COM1-9, LPT1-9), forbidden characters (: * ? \" < > |), ASCII control chars (0x00-0x1F), or components with trailing space/period. The individual problems are logged via Errorln first, then the aggregate error is returned. On non-Windows the same problems are only logged as Info and the alias proceeds.
Solutions
- Rename the alias to avoid reserved device names and the chars : * ? \" < > | and trailing space/period.
- Move the build off Windows for affected aliases, or pre-process aliases to sanitize Windows-illegal components.
- Add a pre-build lint that rejects Windows-invalid alias segments regardless of build OS.
Example fix
--- # before (fails on Windows) aliases: - "help:nlp" # after aliases: - "help-nlp" ---
Defensive patterns
Strategy: validation
Validate before calling
var reserved = []string{"CON","PRN","AUX","NUL","COM0","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT0","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"}
func windowsSafeAlias(a string) error {
if strings.ContainsAny(a, `:*?\"<>|`) { return fmt.Errorf("bad char") }
for _, c := range strings.Split(path.Clean(filepath.ToSlash(a)), "/") {
for _, r := range reserved { if c == r { return fmt.Errorf("reserved") } }
if strings.TrimRight(c, " .") != c { return fmt.Errorf("trailing space/dot") }
}
return nil
} Prevention
- Validate aliases against Windows rules even when building on Unix, for portability.
- Avoid colons, reserved device names, and trailing dots/spaces in aliases.
- Add a CI lint that runs the windowsSafeAlias check on all front matter.
When it happens
Trigger: Building on Windows with a front-matter alias containing a Windows-reserved name or forbidden char, e.g. aliases: ["aux"], aliases: ["a:b"], aliases: ["file."] — the publish step then aborts for that alias. Cross-platform teams hit it when a Linux/macOS-authored alias is fine there but fails on a Windows CI/colleague.
Common situations: Aliases with colons (common in some URL schemes), trailing dots, reserved device names, or question marks; content authored on case-sensitive OSes reaching a Windows builder; CI matrix that includes windows-latest.
Related errors
- alias "" is an empty string
- alias " " resolves to website root directory
- alias " " traverses outside the website root directory
- archetype directory ( ) not supported
- contentNodeToContentNodesPage: unexpected type %T
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/63ceb98919cf0f83.
Report an issue: GitHub.
Appendix: source
Thrown at hugolib/alias.go:172
continue
}
}
for _, comp := range components {
if strings.HasSuffix(comp, " ") || strings.HasSuffix(comp, ".") {
msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains component with a trailing space or period, problematic on Windows", originalAlias))
}
for _, r := range reservedNames {
if comp == r {
msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains component with reserved name \"%s\" on Windows", originalAlias, r))
}
}
}
if len(msgs) > 0 {
if runtime.GOOS == "windows" {
for _, m := range msgs {
a.log.Errorln(m)
}
return "", fmt.Errorf("cannot create \"%s\": Windows filename restriction", originalAlias)
}
for _, m := range msgs {
a.log.Infoln(m)
}
}
// Add the final touch. When the alias does not already end in one of the
// output format's configured suffixes, treat it as a directory and append
// the format's base name and suffix (e.g. index.html).
alias = strings.TrimPrefix(alias, "/")
baseFile := of.BaseName + of.MediaType.FirstSuffix.FullSuffix
if strings.HasSuffix(alias, "/") {
alias = alias + baseFile
} else if !pathHasOutputFormatSuffix(alias, of) {
alias = alias + "/" + baseFile
}
return filepath.FromSlash(alias), nilView on GitHub (pinned to 52c9bd7908)