gohugoio/hugo · warning

alias " " resolves to website root directory

Error message

alias "%s" resolves to website root directory

What it means

Returned by targetPathAlias when path.Clean of the alias equals "/" (the website root) and the aliasHandler was constructed with allowRoot=false. Writing an alias over the site root would clobber index.html, so it is blocked. The publishDestAlias entry point (used for page aliases) passes allowRoot=false; publishDestAliasWithAllowRoot may pass true.

Solutions

  1. Remove the "/" alias from the page's front matter; use a distinct path like "/home/" or "/index-alias/".
  2. If a root alias is genuinely intended (rare), use the internal API path that sets allowRoot=true, but note this overwrites the homepage redirect.
  3. Lint front matter to reject aliases that path.Clean to "/".

Example fix

---
# before
aliases:
  - "/"
# after
aliases:
  - "/old-home/"
---
Defensive patterns

Strategy: validation

Validate before calling

func cleanAlias(a string) (string, error) {
    c := path.Clean(filepath.ToSlash(a))
    if c == "/" { return "", fmt.Errorf("alias resolves to root") }
    return c, nil
}

Prevention

When it happens

Trigger: A page front-matter aliases entry that is exactly "/" or collapses to it (e.g. "./" , "//"). Triggered during site publish when Hugo renders redirect pages for each alias.

Common situations: Author mistakenly sets aliases: ["/"] thinking it redirects to the homepage; a templated alias built from a path variable that becomes root; importing content from another SSG whose root alias semantics differ.

Related errors


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

Appendix: source

Thrown at hugolib/alias.go:132

	}

	if s.conf.RelativeURLs || s.conf.CanonifyURLs {
		pd.AbsURLPath = s.absURLPath(targetPath)
	}

	return s.publisher.Publish(pd)
}

func (a aliasHandler) targetPathAlias(src string, of output.Format) (string, error) {
	originalAlias := src
	if len(src) <= 0 {
		return "", fmt.Errorf("alias \"\" is an empty string")
	}

	alias := path.Clean(filepath.ToSlash(src))

	if !a.allowRoot && alias == "/" {
		return "", fmt.Errorf("alias \"%s\" resolves to website root directory", originalAlias)
	}

	components := strings.Split(alias, "/")

	// Validate against directory traversal
	if components[0] == ".." {
		return "", fmt.Errorf("alias \"%s\" traverses outside the website root directory", originalAlias)
	}

	// Handle Windows file and directory naming restrictions
	// See "Naming Files, Paths, and Namespaces" on MSDN
	// https://msdn.microsoft.com/en-us/library/aa365247%28v=VS.85%29.aspx?f=255&MSPPError=-2147217396
	msgs := []string{}
	reservedNames := []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"}

	if strings.ContainsAny(alias, ":*?\"<>|") {
		msgs = append(msgs, fmt.Sprintf("Alias \"%s\" contains invalid characters on Windows: : * ? \" < > |", originalAlias))
	}

View on GitHub (pinned to 52c9bd7908)