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 bodiesView on GitHub (pinned to 50e54ee279)
Solutions
- Add a root directive (Caddyfile) or set root on the enclosing route so {http.vars.root} resolves
- Or set the templates handler's own file_root (Caddyfile: templates { file_root /path })
- Verify the placeholder expands by logging {http.vars.root} in an access log or respond directive
- 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
- Always pair templates-with-file-functions and a root directive in the same route
- Or set templates { file_root } explicitly to decouple from route vars
- Smoke-test pages that use include after any route restructuring
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
- delimiters must consist of exactly two elements: opening and
- %v is not a directory
- reading default Caddyfile: %v
- parsing environment file: %v
- can't parse line %d; line should be in KEY=VALUE format
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/f5a19adf08354ba5.
Report an issue: GitHub.