caddyserver/caddy · error

%v is not a directory

Error message

%v is not a directory

What it means

Returned by the templates module's listFiles function when the path given exists and was opened successfully but is not a directory (stat.IsDir() is false). The function then cannot Readdir it.

Source

Thrown at modules/caddyhttp/templates/tplcontext.go:409

// funcListFiles reads and returns a slice of names from the given
// directory relative to the root of c.
func (c TemplateContext) funcListFiles(name string) ([]string, error) {
	if c.Root == nil {
		return nil, fmt.Errorf("root file system not specified")
	}

	dir, err := c.Root.Open(path.Clean(name))
	if err != nil {
		return nil, err
	}
	defer dir.Close()

	stat, err := dir.Stat()
	if err != nil {
		return nil, err
	}
	if !stat.IsDir() {
		return nil, fmt.Errorf("%v is not a directory", name)
	}

	dirInfo, err := dir.Readdir(0)
	if err != nil {
		return nil, err
	}

	names := make([]string, len(dirInfo))
	for i, fileInfo := range dirInfo {
		names[i] = fileInfo.Name()
	}

	return names, nil
}

// funcFileExists returns true if filename can be opened successfully.
func (c TemplateContext) funcFileExists(filename string) (bool, error) {
	if c.Root == nil {

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Point listFiles at a directory, e.g. {{ listFiles "/posts" }} or use path.Dir of the file
  2. Guard with {{ if (stat .).IsDir }} style checks or split files vs dirs before calling
  3. Log or render the offending path temporarily to see what the placeholder resolves to
  4. Trim trailing filenames from computed paths in the template

Example fix

<!-- before -->
{{ listFiles "/posts/2024/post.md" }}

<!-- after -->
{{ listFiles "/posts/2024" }}
Defensive patterns

Strategy: type-guard

Type guard

{{ $s := stat "/posts/2024" }}{{ if $s.IsDir }}{{ listFiles "/posts/2024" }}{{ else }}not a directory{{ end }}

Prevention

When it happens

Trigger: {{ listFiles "notes.txt" }} where notes.txt is a regular file; or a dynamic path built from a placeholder that resolves to a file name instead of a folder.

Common situations: Passing a file path where a directory was intended, using '.' on a root that maps to a single file, or template logic like {{ listFiles .Path }} where .Path points at an article file rather than its containing directory.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/7ec4aa12e156a4c9. Report an issue: GitHub.