gohugoio/hugo · error

html/template: pattern matches no files: %#q

Error message

html/template: pattern matches no files: %#q

What it means

Returned by parseGlob (backing ParseGlob and t.ParseGlob) when filepath.Glob succeeds but matches zero files. ParseGlob requires the pattern to match at least one file. The %#q quotes the offending pattern.

Source

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

// When parsing multiple files with the same name in different directories,
// the last one mentioned will be the one that results.
//
// ParseGlob returns an error if t or any associated template has already been executed.
func (t *Template) ParseGlob(pattern string) (*Template, error) {
	return parseGlob(t, pattern)
}

// parseGlob is the implementation of the function and method ParseGlob.
func parseGlob(t *Template, pattern string) (*Template, error) {
	if err := t.checkCanParse(); err != nil {
		return nil, err
	}
	filenames, err := filepath.Glob(pattern)
	if err != nil {
		return nil, err
	}
	if len(filenames) == 0 {
		return nil, fmt.Errorf("html/template: pattern matches no files: %#q", pattern)
	}
	return parseFiles(t, readFileOS, filenames...)
}

// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
// and whether the value has a meaningful truth value. This is the definition of
// truth used by if and other such actions.
func IsTrue(val any) (truth, ok bool) {
	return template.IsTrue(val)
}

// ParseFS is like [ParseFiles] or [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 ParseFS(fs fs.FS, patterns ...string) (*Template, error) {
	return parseFS(nil, fs, patterns)
}

View on GitHub (pinned to 52c9bd7908)

Solutions

  1. Print/log the absolute pattern and the resolved matches (filepath.Glob) to confirm the path.
  2. Ensure the working directory or use absolute paths / an embed.FS rooted at the binary.
  3. Correct the glob (e.g. add 'layouts/*.html') so it matches at least one file.
  4. Use ParseFS with go:embed so file resolution is independent of cwd.

Example fix

// before
t, err := template.ParseGlob("temlates/*.html") // typo, no match

// after
matches, _ := filepath.Glob("templates/*.html")
if len(matches) == 0 { return fmt.Errorf("no templates under %q", absDir) }
t, err := template.ParseGlob("templates/*.html")
Defensive patterns

Strategy: validation

Validate before calling

func parseGlobSafe(pattern string) (*template.Template, error) {
    matches, err := filepath.Glob(pattern)
    if err != nil { return nil, err }
    if len(matches) == 0 {
        abs, _ := filepath.Abs(pattern)
        return nil, fmt.Errorf("glob %q (abs %q) matched no files", pattern, abs)
    }
    return template.ParseGlob(pattern)
}

Try / catch

t, err := template.ParseGlob(pattern)
if err != nil && strings.Contains(err.Error(), "pattern matches no files") {
    cwd, _ := os.Getwd()
    // fix cwd or switch to absolute/embed-based pattern, then retry
    return template.ParseGlob(filepath.Join(absRoot, pattern))
}

Prevention

When it happens

Trigger: Calling template.ParseGlob(pattern) or t.ParseGlob(pattern) where pattern matches nothing under the current working directory (typo, wrong dir, missing files, wrong glob syntax that matches nothing).

Common situations: Running the binary from a different working directory than expected so relative globs miss; deploying without the templates directory; a typo in the glob (e.g. missing extension); CI that runs in a sparse checkout missing layout files.

Related errors


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