gohugoio/hugo · error

template: pattern matches no files: %#q

Error message

template: pattern matches no files: %#q

What it means

Returned by parseFS (backing ParseFS and t.ParseFS) when fs.Glob on the provided fs.FS for a pattern returns an empty list. Unlike ParseGlob's os-based variant, this operates on an arbitrary io/fs.FS (embed, memory, etc.) and requires each pattern to match at least one file. The %#q quotes the pattern.

Source

Thrown at tpl/internal/go_templates/htmltemplate/template.go:512

}

// ParseFS is like [Template.ParseFiles] or [Template.ParseGlob] but reads from the file system fs
// instead of the host operating system's file system.
// It accepts a list of glob patterns.
// (Note that most file names serve as glob patterns matching only themselves.)
func (t *Template) ParseFS(fs fs.FS, patterns ...string) (*Template, error) {
	return parseFS(t, fs, patterns)
}

func parseFS(t *Template, fsys fs.FS, patterns []string) (*Template, error) {
	var filenames []string
	for _, pattern := range patterns {
		list, err := fs.Glob(fsys, pattern)
		if err != nil {
			return nil, err
		}
		if len(list) == 0 {
			return nil, fmt.Errorf("template: pattern matches no files: %#q", pattern)
		}
		filenames = append(filenames, list...)
	}
	return parseFiles(t, readFileFS(fsys), filenames...)
}

func readFileOS(file string) (name string, b []byte, err error) {
	name = filepath.Base(file)
	b, err = os.ReadFile(file)
	return
}

func readFileFS(fsys fs.FS) func(string) (string, []byte, error) {
	return func(file string) (name string, b []byte, err error) {
		name = path.Base(file)
		b, err = fs.ReadFile(fsys, file)
		return
	}

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Verify the file exists via fs.ReadDir/fs.Stat on the fsys at the expected path.
  2. Check the embed directive //go:embed includes the needed files/dirs and rebuild.
  3. Correct the pattern (no leading slash for embed.FS; match the exact layout).
  4. Log fsys contents (fs.WalkDir) once during init to catch mismatches early.

Example fix

// before
//go:embed templats/*
var tpls embed.FS
t, err := template.ParseFS(tpls, "templats/*.html") // typo in embed too

// after
//go:embed templates/*.html
var tpls embed.FS
t, err := template.ParseFS(tpls, "templates/*.html")
Defensive patterns

Strategy: validation

Validate before calling

func parseFSSafe(fsys fs.FS, patterns ...string) (*template.Template, error) {
    for _, p := range patterns {
        list, err := fs.Glob(fsys, p)
        if err != nil { return nil, err }
        if len(list) == 0 {
            return nil, fmt.Errorf("pattern %q matched nothing in FS", p)
        }
    }
    return template.ParseFS(fsys, patterns...)
}

Try / catch

t, err := template.ParseFS(fsys, patterns...)
if err != nil && strings.Contains(err.Error(), "pattern matches no files") {
    // dump FS tree to diagnose embed/path issues
    _ = fs.WalkDir(fsys, ".", func(p string, d fs.DirEntry, e error) error { return nil })
}

Prevention

When it happens

Trigger: Calling template.ParseFS(fsys, patterns...) or t.ParseFS(fsys, patterns...) where one of the patterns matches no entries in fsys (typo, missing file in the embed directive, wrong path prefix in the FS).

Common situations: Embed directives that forgot a file or directory; FS path prefix mismatch (e.g. leading slash in embed.FS); renaming a template file but not the pattern; pointing ParseFS at the wrong fs.FS instance.

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/e0c56060e38f95b5. Report an issue: GitHub.