gohugoio/hugo · error

page reference %q is ambiguous

Error message

page reference %q is ambiguous

What it means

Hugo's pageFinder resolves a page reference (from ref/relref shortcodes, .GetPage, or link render hooks) via a reverse index keyed by the base filename without identifiers. When the same base name (e.g. `about.md`) exists in multiple sections, the index stores an `ambiguousContentNode` sentinel, and any simple (no-slash) lookup of that name fails with this error because Hugo cannot know which page you meant.

Source

Thrown at hugolib/pagecollections.go:218

	if hadExtension && s.home != nil && s.home.File() != nil {
		if n, err := c.getContentNodeFromRefReverseLookup(inRef, s.home.File().FileInfo()); n != nil || err != nil {
			return n, err
		}
	}

	var doSimpleLookup bool
	if isReflink || context == nil {
		slashCount := strings.Count(inRef, "/")
		doSimpleLookup = slashCount == 0
	}

	if !doSimpleLookup {
		return nil, nil
	}

	n = c.pm.pageReverseIndex.Get(nameNoIdentifier)
	if n == ambiguousContentNode {
		return nil, fmt.Errorf("page reference %q is ambiguous", inRef)
	}

	return n, nil
}

func (c *pageFinder) getContentNodeFromRefReverseLookup(ref string, fi hugofs.FileMetaInfo) (contentNode, error) {
	s := c.pm.s
	meta := fi.Meta()
	dir := meta.Filename
	if !fi.IsDir() {
		dir = filepath.Dir(meta.Filename)
	}

	realFilename := filepath.Join(dir, ref)

	pcs, err := s.BaseFs.Content.ReverseLookup(realFilename, true)
	if err != nil {
		return nil, err

View on GitHub ↗ (pinned to 8a468df065)

Solutions

  1. Qualify the reference with its section path: `{{< ref "/company/about" >}}` or `.GetPage "/company/about.md"` instead of the bare name.
  2. Search the content tree for duplicates (`find content -name 'about*'`) and rename one file if the duplication is accidental.
  3. For links relative to the current page, use a leading `./` or the page's full path so the reverse-index simple lookup is never used.

Example fix

<!-- before -->
{{< ref "about" >}}
<!-- after -->
{{< ref "/company/about" >}}
Defensive patterns

Strategy: validation

Validate before calling

// Use unambiguous page refs in templates/content:
// {{ .Site.GetPage "/posts/my-post" }} — full path from content root
// instead of a bare filename like {{ .Site.GetPage "my-post" }}
// Audit for bare refs:
// grep -rn 'GetPage "' layouts/ content/ | grep -v 'GetPage "/'

Try / catch

p, err := s.GetPage(ref)
if err != nil {
    return fmt.Errorf("resolve %q: use a full path from the content root to disambiguate: %w", ref, err)
}

Prevention

When it happens

Trigger: Calling `.GetPage "about"`, `{{< ref "about" >}}`, or `{{< relref "mypage.md" >}}` with a bare filename (no path separators) when two or more content files share that base name in different directories, e.g. `content/blog/about.md` and `content/company/about.md`. Only the simple-lookup path at pagecollections.go:216 hits this; path-qualified refs bypass it.

Common situations: Large multilingual or multi-section sites with recurring filenames like `index.md`, `overview.md`, or `faq.md`; content migrated from other SSGs where duplicate slugs were fine; shortcodes copied from docs that use bare filenames; sites that grew a second section containing a filename that used to be unique.

Related errors


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