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, errView on GitHub ↗ (pinned to 8a468df065)
Solutions
- Qualify the reference with its section path: `{{< ref "/company/about" >}}` or `.GetPage "/company/about.md"` instead of the bare name.
- Search the content tree for duplicates (`find content -name 'about*'`) and rename one file if the duplication is accidental.
- 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
- Always reference pages by full content-root-relative path ("/posts/foo") rather than bare filenames
- Avoid duplicate page filenames across sections when you rely on short refs
- When using relref/ref shortcodes, pass the section-qualified path
- Add a CI build (hugo --panicOnWarning) so ambiguous refs fail fast
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
- error processing file %q
- error building site: %w
- no existing content directory configured for this project
- failed to resolve %q to an archetype template
- failed to create target directory for %q: %w
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/0552f1e258e09cce.json.
Report an issue: GitHub ↗.