gohugoio/hugo · error
unwrapPage: %T not supported
Error message
unwrapPage: %T not supported
What it means
Raised by `unwrapPage` in hugolib/page_unwrap.go:42, a helper used in page equality checks and comparisons (e.g. `.IsAncestor`, `.Eq`, `in`-style checks). It accepts a `*pageState`, a `pageWrapper`, a `types.Unwrapper`, a `page.Page`, or nil; any other type — a string, a resource, a map, a slice of pages — falls to the default case and this error reports the unsupported Go type via `%T`. Callers going through `mustUnwrapPage` turn it into a panic.
Source
Thrown at hugolib/page_unwrap.go:42
type pageWrapper interface {
page() page.Page
}
// unwrapPage is used in equality checks and similar.
func unwrapPage(in any) (page.Page, error) {
switch v := in.(type) {
case *pageState:
return v, nil
case pageWrapper:
return v.page(), nil
case types.Unwrapper:
return unwrapPage(v.Unwrapv())
case page.Page:
return v, nil
case nil:
return nil, nil
default:
return nil, fmt.Errorf("unwrapPage: %T not supported", in)
}
}
func mustUnwrapPage(in any) page.Page {
p, err := unwrapPage(in)
if err != nil {
panic(err)
}
return p
}
View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Find the template call in the error's stack/context and pass an actual Page object (e.g. `.Site.GetPage "/about"`) instead of a string/permalink.
- For menu entries, use `.Page` (with a nil check) rather than `.URL` when calling page-comparison methods.
- If comparing by path is what you want, compare strings directly (`eq $p.RelPermalink $other`) instead of using page equality helpers.
Example fix
{{/* before */}}
{{ if .IsAncestor .Site.Home.RelPermalink }}...{{ end }}
{{/* after */}}
{{ if .IsAncestor .Site.Home }}...{{ end }} Defensive patterns
Strategy: type-guard
Type guard
func asPage(v any) (page.Page, bool) {
p, ok := v.(page.Page)
return p, ok
}
// in templates: {{ if eq (printf "%T" .) "*hugolib.pageState" }} — or better: {{ with .Page }}...{{ end }} Prevention
- Only pass real Page values to functions/partials expecting pages — don't hand them shortcode contexts, Sites, or dicts
- In templates, use `.Page` from shortcode/render-hook contexts to obtain the underlying page before passing it on
- When writing template code that accepts mixed input, guard with `with`/type checks before calling page-only methods
When it happens
Trigger: Templates passing a non-Page value where a Page is expected: e.g. `{{ if $p.Eq .Site.Home.Permalink }}` (a string), `.IsAncestor .Sections` (a slice), or passing a Resource/partial result into page-comparison functions.
Common situations: Template code comparing a page against a path or permalink string instead of the page object; iterating a menu and passing `.URL` instead of `.Page`; custom partials that lose the page type by converting it; theme incompatibilities after Hugo type changes.
Related errors
- arguments to symdiff must be slices or arrays
- can't iterate over %T
- text must be a string
- first argument must be a map
- type %T not supported
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/5402eba0649b8774.json.
Report an issue: GitHub ↗.