gohugoio/hugo · error

cannot create "%s": Windows filename restriction

Error message

cannot create "%s": Windows filename restriction

What it means

Hugo validates alias paths against Windows filename rules (reserved device names like CON/PRN/AUX/NUL/COM1-9/LPT1-9, characters `: * ? " < > |`, ASCII control codes, and components ending in a space or period). On non-Windows hosts these problems are only logged at info level, but when building on Windows (runtime.GOOS == "windows") the file genuinely cannot be created, so each violation is logged as an error and the build fails with this message.

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), nil

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Read the preceding error lines to identify the exact offending alias and violation, then rename that alias component (e.g. `aux` → `auxiliary`, drop `?`/`:` characters, remove trailing dots/spaces).
  2. Strip query strings from aliases — an alias is a path, not a full URL; `/page?id=3` should become a plain path or be handled by server-side redirects.
  3. If the legacy URL genuinely requires forbidden characters, handle that redirect at the web server/CDN layer instead of a Hugo alias.
  4. As a workaround, build on a non-Windows machine or WSL, where these are downgraded to info-level warnings (but the published files may still be unusable on Windows filesystems).

Example fix

# before
---
aliases: ["/docs/aux/setup", "/faq?old"]
---

# after
---
aliases: ["/docs/auxiliary/setup", "/faq-old"]
---
Defensive patterns

Strategy: validation

Validate before calling

var winReserved = regexp.MustCompile(`(?i)^(con|prn|aux|nul|com[1-9]|lpt[1-9])($|\.)`)
func winSafeAlias(a string) bool {
    for _, seg := range strings.Split(path.Clean(a), "/") {
        if winReserved.MatchString(seg) || strings.ContainsAny(seg, `<>:"|?*`) {
            return false
        }
    }
    return true
}

Try / catch

if err != nil && strings.Contains(err.Error(), "Windows filename restriction") {
    // rename the alias segment (e.g. "con" -> "console") and rebuild
}

Prevention

When it happens

Trigger: Building on Windows with a page whose `aliases` entry contains a reserved name component (e.g. `aliases: ["/docs/aux/setup"]`), a forbidden character (`aliases: ["/faq?old"]`, `"/a:b"`), a control character, or a component with a trailing dot or space. The specific violations are printed as separate error lines just before this failure.

Common situations: Cross-platform teams where a site builds fine on Linux/macOS CI but fails for a contributor on Windows; aliases copied from old URLs containing query strings (`?`) or colons; directory names like `con`, `nul`, or `lpt1` appearing innocently in migrated URL structures.

Related errors


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/63ceb98919cf0f83.json. Report an issue: GitHub ↗.