gohugoio/hugo · error
invalid path %q
Error message
invalid path %q
What it means
Returned by toPathSitesMap in hugolib/pagesfromdata/pagesfromgotmpl.go:74 when the map passed to a content adapter's AddPage (from a _content.gotmpl template) has a 'path' value that cannot be cast to a string. Every page created from a content adapter must have a string path, so Hugo rejects the entry immediately. Note the message interpolates the (empty) cast result, so it typically reads invalid path "".
Source
Thrown at hugolib/pagesfromdata/pagesfromgotmpl.go:74
// The return value will always be an empty string.
EnableAllLanguages() string
}
var _ PagesFromDataTemplateContext = (*pagesFromDataTemplateContext)(nil)
type pagesFromDataTemplateContext struct {
p *PagesFromTemplate
}
func (p *pagesFromDataTemplateContext) toPathSitesMap(v any) (string, map[string]any, map[string]any, error) {
m, err := hmaps.ToStringMapE(v)
if err != nil {
return "", nil, nil, err
}
path, err := cast.ToStringE(m["path"])
if err != nil {
return "", nil, nil, fmt.Errorf("invalid path %q", path)
}
sites := hmaps.ToStringMap(m["sites"])
return path, sites, m, nil
}
func (p *pagesFromDataTemplateContext) AddPage(v any) (string, error) {
path, sites, m, err := p.toPathSitesMap(v)
if err != nil {
return "", err
}
hash, hasChanged := p.p.buildState.checkHasChangedAndSetSourceInfo(path, sites, m)
if !hasChanged {
return "", nil
}
View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Ensure the dict passed to .AddPage has a 'path' key whose value is a plain string (e.g. "path" (printf "posts/%s" .id)).
- Print the offending item with warnf/debug in the template to see the actual type of .path.
- Coerce values explicitly in the template with the string func before adding the page.
- Validate the remote data shape (transform.Unmarshal result) before iterating.
Example fix
{{/* before: path is a map */}}
{{ $.AddPage (dict "path" .slugObject "title" .title) }}
{{/* after: path is a string */}}
{{ $.AddPage (dict "path" (string .slugObject.slug) "title" .title) }} Defensive patterns
Strategy: validation
Validate before calling
// Validate paths passed to AddPage in content adapters (_content.gotmpl)
{{ $path := "posts/my-post" }}
{{ if or (strings.HasPrefix $path "/") (eq $path "") (in $path "..") }}
{{ errorf "bad page path %q" $path }}
{{ end }}
{{ $.AddPage (dict "path" $path "title" "My Post") }} Prevention
- In `_content.gotmpl`, always pass relative, clean paths (no leading slash, no `..`, non-empty) to AddPage/AddResource
- Sanitize externally sourced slugs (e.g. from an API) with `path.Clean` / `urlize` before using them as page paths
- Add a test site fixture in CI exercising the content adapter with representative data
When it happens
Trigger: Calling $.AddPage in _content.gotmpl with a dict whose 'path' key is a non-string-castable value (a slice, map, or nil object from remote JSON), or where cast.ToStringE fails on the value type.
Common situations: Content adapters built over remote APIs where the expected field is missing or nested (passing the whole object instead of .path); building the path with a template pipeline that yields a slice; typo'd key so 'path' is absent and a non-castable zero value flows in; migrating data whose id field is numeric-array or object typed.
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/846e5852bbbd0f81.json.
Report an issue: GitHub ↗.