gohugoio/hugo · warning

duplicate menu entry with identifier

Error message

duplicate menu entry with identifier %q in menu %q

What it means

While assembling site navigation, two menu entries resolved to the same identifier (KeyName) within the same menu. Hugo logs this as a warning (s.Log.Warnln) and keeps only the first entry, so it is non-fatal but produces an incomplete/incorrect menu. The duplicate typically arises when page front matter declares a menu entry whose identifier collides with one from sectionPagesMenu, another page, or the explicit menus config.

Solutions

  1. Make each menu entry's identifier unique by setting an explicit identifier (or name) in front matter: menu: main: { identifier: "unique-id" }.
  2. Decide whether the duplicate should come from sectionPagesMenu or from front matter, and remove the other source.
  3. Rebuild and confirm the warning no longer appears; verify the rendered menu has the intended entries.

Example fix

// before (two pages, both)
+++ 
menu: { main: { name: "Docs" } }
+++

// after (give unique identifiers)
+++ 
menu: { main: { identifier: "docs-intro", name: "Docs" } }
+++
Defensive patterns

Strategy: validation

Validate before calling

// Before building, ensure every menu entry identifier is unique per menu.
func validateMenuIDs(entries []MenuEntry) error {
    seen := map[string]bool{}
    for _, e := range entries {
        key := e.Menu + "/" + e.Identifier
        if seen[key] {
            return fmt.Errorf("duplicate menu entry %q in menu %q", e.Identifier, e.Menu)
        }
        seen[key] = true
    }
    return nil
}

Prevention

When it happens

Trigger: Two pages both list menu: main under front matter with the same name/identifier; a page-level menu entry collides with an auto-generated sectionPagesMenu entry (site.go:1484-1490 checks the flat[twoD{name,key}] map before inserting).

Common situations: Setting sectionPagesMenu: main globally while also adding explicit menu entries in page front matter; multiple pages sharing the same title used as the menu identifier; renaming pages without updating menu identifiers.

Related errors


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

Appendix: source

Thrown at hugolib/site.go:1487

					Name:       p.LinkTitle(),
					Weight:     p.Weight(),
				},
				Page: p,
			}

			navigation.SetPageValues(&me, p)
			flat[twoD{sectionPagesMenu, me.KeyName()}] = &me
			return false, nil
		}); err != nil {
			return nil, err
		}
	}

	// Add menu entries provided by pages
	if err := s.pageMap.forEachPage(pagePredicates.ShouldListGlobal, func(p *pageState) (bool, error) {
		for name, me := range p.pageMenus.menus() {
			if _, ok := flat[twoD{name, me.KeyName()}]; ok {
				err := p.wrapError(fmt.Errorf("duplicate menu entry with identifier %q in menu %q", me.KeyName(), name))
				s.Log.Warnln(err)
				continue
			}
			flat[twoD{name, me.KeyName()}] = me
		}
		return false, nil
	}); err != nil {
		return nil, err
	}

	// Create Children Menus First
	for _, e := range flat {
		if e.Parent != "" {
			children[twoD{e.Menu, e.Parent}] = children[twoD{e.Menu, e.Parent}].Add(e)
		}
	}

	// Placing Children in Parents (in flat)

View on GitHub (pinned to 52c9bd7908)