{"record":{"id":"4dd7486211d4d77c","repo":"gohugoio/hugo","slug":"template-no-files-named-in-call-to-parsefiles","errorCode":null,"errorMessage":"template: no files named in call to ParseFiles","messagePattern":"template: no files named in call to ParseFiles","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tpl/internal/go_templates/texttemplate/helper.go","lineNumber":65,"sourceCode":"// Since the templates created by ParseFiles are named by the base\n// (see [filepath.Base]) names of the argument files, t should usually have the\n// name of one of the (base) names of the files. If it does not, depending on\n// t's contents before calling ParseFiles, t.Execute may fail. In that\n// case use t.ExecuteTemplate to execute a valid template.\n//\n// When parsing multiple files with the same name in different directories,\n// the last one mentioned will be the one that results.\nfunc (t *Template) ParseFiles(filenames ...string) (*Template, error) {\n\tt.init()\n\treturn parseFiles(t, readFileOS, filenames...)\n}\n\n// parseFiles is the helper for the method and function. If the argument\n// template is nil, it is created from the first file.\nfunc parseFiles(t *Template, readFile func(string) (string, []byte, error), filenames ...string) (*Template, error) {\n\tif len(filenames) == 0 {\n\t\t// Not really a problem, but be consistent.\n\t\treturn nil, fmt.Errorf(\"template: no files named in call to ParseFiles\")\n\t}\n\tfor _, filename := range filenames {\n\t\tname, b, err := readFile(filename)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\ts := string(b)\n\t\t// First template becomes return value if not already defined,\n\t\t// and we use that one for subsequent New calls to associate\n\t\t// all the templates together. Also, if this file has the same name\n\t\t// as t, this file becomes the contents of t, so\n\t\t//  t, err := New(name).Funcs(xxx).ParseFiles(name)\n\t\t// works. Otherwise we create a new template associated with t.\n\t\tvar tmpl *Template\n\t\tif t == nil {\n\t\t\tt = New(name)\n\t\t}\n\t\tif name == t.Name() {","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/gohugoio/hugo/blob/52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2/tpl/internal/go_templates/texttemplate/helper.go#L47-L83","documentation":"Returned by template.ParseFiles (function and method form) when the variadic filenames slice is empty. Hugo's vendored Go text/template requires at least one file and treats a zero-length call as a programmer error rather than silently returning an empty template. The guard lives in parseFiles at helper.go:63-66.","triggerScenarios":"Calling template.New(\"x\").ParseFiles() with no arguments, or passing a computed []string that happens to be empty, e.g. ParseFiles(files...) where files was populated by a filter/glob that returned nothing.","commonSituations":"Dynamically building the file list from config or globbing and the source yields no matches; refactoring that drops the filename argument; unit tests that stub file discovery to return an empty slice.","solutions":["Pass at least one existing filename to ParseFiles.","Guard the call site: only invoke ParseFiles when len(files) > 0, otherwise return a descriptive error.","Trace upstream: verify the slice population logic (glob results, config reads, directory walks) is not returning empty unexpectedly."],"exampleFix":"// before\nt, err := template.New(\"x\").ParseFiles(files...)\n\n// after\nif len(files) == 0 {\n    return fmt.Errorf(\"no template files configured\")\n}\nt, err := template.New(\"x\").ParseFiles(files...)","handlingStrategy":"validation","validationCode":"if len(filenames) == 0 {\n    return nil, fmt.Errorf(\"no template files to parse\")\n}\nt, err := template.New(\"x\").ParseFiles(filenames...)","typeGuard":null,"tryCatchPattern":"t, err := template.ParseFiles(files...)\nif err != nil {\n    return fmt.Errorf(\"loading templates: %w\", err)\n}","preventionTips":["Assert the file slice is non-empty before calling ParseFiles.","Log how many files were discovered by the upstream glob/walk so an empty result is visible."],"tags":["template","go","parse","configuration"],"backgroundTag":null,"analyzedSha":"52c9bd7908b4d02d4d0ff8f82a888834d6ee10d2","analyzedAt":"2026-08-09T21:49:36.660Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}