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

  1. Rename the adapter file to _content.gotmpl — that is the only supported extension for pages-from-data adapters.
  2. If the file is plain data, move it to the data/ directory (or load it inside the .gotmpl via resources) instead of content/.
  3. 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

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


AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31). Data as JSON: /data/errors/63d68990f349077e.json. Report an issue: GitHub ↗.