gohugoio/hugo · error
unsupported data file extension
Error message
unsupported data file extension %q
What it means
Returned by addPagesFromGoTmplFi when a file routed as TypeContentData (a Go-template data file that generates pages) has an extension that is not a Go-template extension (files.IsGoTmplExt returns false). Hugo's data-driven page generation requires .tmpl/.gotmpl/.html templates; any other extension placed in the content data path is unsupported.
Solutions
- If the file is a page-generating template, rename it to use .tmpl or .gotmpl (e.g. mypages.html.tmpl).
- If the file is meant as data, move it to /data (Hugo's data source) instead of /content.
- Review mediaTypes and module mounts to ensure the extension is classified as intended.
- Check the path type logic: only files the path parser tags as TypeContentData reach this branch.
Example fix
# before /content/books.json (rejected: unsupported data file extension ".json") # after /data/books.json (data file) OR /content/books.tmpl (page-generating template)
Defensive patterns
Strategy: type-guard
Validate before calling
func isGoTmplExt(ext string) bool {
switch strings.ToLower(strings.TrimPrefix(ext, ".")) {
case "tmpl", "gotmpl", "html": return true
}
return false
} Type guard
func isContentDataTemplate(fi hugofs.FileMetaInfo) bool {
return fi.Meta().PathInfo != nil && fi.Meta().PathInfo.Type() == paths.TypeContentData && isGoTmplExt(fi.Meta().PathInfo.Ext())
} Prevention
- Use .tmpl/.gotmpl/.html for content-data page generators under /content.
- Put non-template data under /data, not /content.
- Review mediaTypes/module mounts when changing how extensions are classified.
When it happens
Trigger: A file under /content with a path type that routes it into the content-data (pages-from-template) pipeline but whose extension is not .tmpl/.gotmpl/.html — e.g. a misplaced .json, .yaml, .csv, or .txt that the path classifier treated as content data. This indicates a path/classification mismatch.
Common situations: Placing a data file (.json/.yaml) directly in /content expecting it to be data when Hugo expects it under /data; a content-nested template misnamed; a custom mediaTypes/paths config reclassifying extensions unexpectedly; upgrading Hugo where content-data routing changed.
Related errors
- contentNodeToContentNodesPage: unexpected type %T
- failed to create page from file
- failed to create page from pageMetaSource
- failed to create page meta from file
- failed to create term page
AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09).
Data as JSON: /api/errors/63d68990f349077e.
Report an issue: GitHub.
Appendix: source
Thrown at hugolib/content_map.go:333
}
m.treePages.InsertWithLock(pm.pathInfo.Base(), pm)
}
return
}
func (m *pageMap) addPagesFromGoTmplFi(fi hugofs.FileMetaInfo, buildConfig *BuildCfg) (pageCount uint64, resourceCount uint64, addErr error) {
meta := fi.Meta()
pi := meta.PathInfo
m.s.Log.Trace(logg.StringFunc(
func() string {
return fmt.Sprintf("insert pages from data file: %q", fi.Meta().Filename)
},
))
if !files.IsGoTmplExt(pi.Ext()) {
addErr = fmt.Errorf("unsupported data file extension %q", pi.Ext())
return
}
sitesMatrix := fi.Meta().SitesMatrix
s := m.s.h.resolveFirstSite(sitesMatrix)
h := s.h
contentAdapter := s.pageMap.treePagesFromTemplateAdapters.Get(pi.Base())
var rebuild bool
if contentAdapter != nil {
// Rebuild
contentAdapter = contentAdapter.CloneForGoTmpl(fi)
rebuild = true
} else {
contentAdapter = pagesfromdata.NewPagesFromTemplate(
pagesfromdata.PagesFromTemplateOptions{
GoTmplFi: fi,View on GitHub (pinned to 52c9bd7908)