caddyserver/caddy · error

root file system not specified

Error message

root file system not specified

What it means

Returned by TemplateContext.readFileToBuffer (backing the 'include' template function) when c.Root is nil, i.e. the template context has no root file system to resolve relative paths against. The templates handler normally sets Root from FileRoot, which defaults to {http.vars.root}.

Source

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

// trusted files. If it is not trusted, be sure to use escaping functions
// in your template.
func (c TemplateContext) funcReadFile(filename string) (string, error) {
	bodyBuf := bufPool.Get().(*bytes.Buffer)
	bodyBuf.Reset()
	defer bufPool.Put(bodyBuf)

	err := c.readFileToBuffer(filename, bodyBuf)
	if err != nil {
		return "", err
	}

	return bodyBuf.String(), nil
}

// readFileToBuffer reads a file into a buffer
func (c TemplateContext) readFileToBuffer(filename string, bodyBuf *bytes.Buffer) error {
	if c.Root == nil {
		return fmt.Errorf("root file system not specified")
	}

	file, err := c.Root.Open(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	_, err = io.Copy(bodyBuf, file)
	if err != nil {
		return err
	}

	return nil
}

// funcHTTPInclude returns the body of a virtual (lightweight) request
// to the given URI on the same server. Note that included bodies

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Add a root directive (Caddyfile) or set root on the enclosing route so {http.vars.root} resolves
  2. Or set the templates handler's own file_root (Caddyfile: templates { file_root /path })
  3. Verify the placeholder expands by logging {http.vars.root} in an access log or respond directive
  4. Avoid include/file functions if the deployment has no file root at all

Example fix

# before
localhost {
    templates
    respond `{{ include "partial.html" }}`
}

# after
localhost {
    root * /srv/site
    templates
    respond `{{ include "partial.html" }}`
}
Defensive patterns

Strategy: validation

Validate before calling

# Caddyfile: ensure root applies before templates
root * /srv
templates

# Debug: confirm the placeholder resolves
respond "root={http.vars.root}"

Prevention

When it happens

Trigger: Using {{ include "file" }} (or any function that reads files, like 'stat') in a context where the root variable is unset: no file_server/root directive set the {http.vars.root} placeholder and FileRoot was not configured on the templates handler.

Common situations: A route with templates but no root directive (common when templates are used for pure string responses without a file server), a root defined on a different route that does not apply to this request, or FileRoot pointing to a variable that is never populated.

Related errors


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