gohugoio/hugo · error
unsupported data file extension %q
Error message
unsupported data file extension %q
What it means
addPagesFromGoTmplFi handles files classified as TypeContentData — content adapters that generate pages from data. Hugo requires these to be Go template files (files.IsGoTmplExt, i.e. .gotmpl); any other extension on a file in that role is rejected. It prevents Hugo from executing a non-template file as a pages-from-data adapter.
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 8a468df065)
Solutions
- Rename the adapter file to _content.gotmpl — that is the only supported extension for pages-from-data adapters.
- If the file is plain data, move it to the data/ directory (or load it inside the .gotmpl via resources) instead of content/.
- Check the docs for content adapters (hugo v0.126+) if the feature is new to the project.
Example fix
// before content/posts/_content.yaml // after content/posts/_content.gotmpl (loads the YAML via resources.Get and calls .AddPage)
Defensive patterns
Strategy: validation
Validate before calling
var dataExts = map[string]bool{".json": true, ".toml": true, ".yaml": true, ".yml": true, ".xml": true, ".csv": true}
if !dataExts[filepath.Ext(path)] {
return fmt.Errorf("unsupported data file %q", path)
} Type guard
func isDataFile(path string) bool {
switch filepath.Ext(path) {
case ".json", ".toml", ".yaml", ".yml", ".xml", ".csv":
return true
}
return false
} Try / catch
if err := site.Build(); err != nil {
if strings.Contains(err.Error(), "unsupported data file extension") {
// remove or rename the offending file in data/
}
return err
} Prevention
- Only place decodable formats (json, toml, yaml, xml, csv) under data/
- Keep README, .md, .txt and editor backup files (~, .swp) out of the data directory
- Add a CI check that lists data/ files with unexpected extensions
When it happens
Trigger: Placing a file named like a content adapter (e.g. _content.<ext>) under content/ where the path parser classifies it as TypeContentData but the extension is not .gotmpl — for example _content.yaml, _content.json, or _content.tmpl.
Common situations: Misnaming the content adapter file _content.tmpl or _content.html instead of _content.gotmpl; assuming the pages-from-data feature accepts raw YAML/JSON data files directly; migrating examples from blog posts that used a different extension.
Related errors
- markup must not be set, use mediaType
- failed to detect target data serialization format
- unsupported transpiler %q; valid values are %q or %q
- 'paginate' configuration setting must be positive to paginat
- babel config %q not found
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/63d68990f349077e.json.
Report an issue: GitHub ↗.