gohugoio/hugo · error
invalid filename
Error message
invalid filename
What it means
The `os.ReadFile` template function cleans the given path and rejects it if the result is empty, ".", or the bare path separator — i.e. it doesn't name an actual file. This guards against reading the working directory root or a meaningless path.
Source
Thrown at tpl/os/os.go:82
func (ns *Namespace) Getenv(key any) (string, error) {
skey, err := cast.ToStringE(key)
if err != nil {
return "", nil
}
if err = ns.deps.ExecHelper.Sec().CheckAllowedGetEnv(skey); err != nil {
return "", err
}
return _os.Getenv(skey), nil
}
// readFile reads the file named by filename in the given filesystem
// and returns the contents as a string.
func readFile(fs afero.Fs, filename string) (string, error) {
filename = filepath.Clean(filename)
if filename == "" || filename == "." || filename == string(_os.PathSeparator) {
return "", errors.New("invalid filename")
}
b, err := afero.ReadFile(fs, filename)
if err != nil {
return "", err
}
return string(b), nil
}
// ReadFile reads the file named by filename relative to the configured WorkingDir.
// It returns the contents as a string.
// There is an upper size limit set at 1 megabytes.
func (ns *Namespace) ReadFile(i any) (string, error) {
s, err := cast.ToStringE(i)
if err != nil {
return "", err
}View on GitHub ↗ (pinned to 8a468df065)
Solutions
- Guard the call: `{{ with $path }}{{ os.ReadFile . }}{{ end }}` so empty values are skipped.
- Check where the path variable comes from (front matter param, site config) and set or default it (`default "data/x.txt" .Params.file`).
- Ensure the path points to a real file relative to the project working directory, not a directory.
Example fix
{{/* before */}}
{{ $c := os.ReadFile .Params.snippet }}
{{/* after */}}
{{ with .Params.snippet }}{{ $c := os.ReadFile . }}{{ end }} Defensive patterns
Strategy: validation
Validate before calling
{{ $path := "data/notes.txt" }}
{{ if and $path (fileExists $path) }}
{{ $content := readFile $path }}
{{ end }} Try / catch
{{ with try (os.ReadFile $path) }}
{{ with .Err }}{{ warnf "readFile %q: %s" $path . }}{{ else }}{{ $content := .Value }}{{ end }}
{{ end }} Prevention
- Never pass an empty or nil path to os.ReadFile/os.FileExists/os.Stat — guard with {{ with $path }} first
- Use project-relative paths inside the project root; Hugo's security model rejects paths that escape it (e.g. ../../ traversal)
- Gate reads behind os.FileExists so optional files don't break the build
When it happens
Trigger: `{{ os.ReadFile "" }}`, `{{ os.ReadFile "." }}`, `{{ os.ReadFile "/" }}`, or a path that filepath.Clean collapses to one of those (e.g. "./", "foo/..").
Common situations: A template variable used as the filename is empty because a page param or site config value is unset; string concatenation producing "" or "/"; iterating over params where some entries lack a path field.
Related errors
- failed to read directory %q: %s
- error building site: %w
- failed to detect format from content
- failed to detect target data serialization format
- templates.Defer cannot be used inside a partialCached partia
AI-assisted analysis of gohugoio/hugo@8a468df065 (2026-07-31).
Data as JSON: /data/errors/74772cb5edab2d12.json.
Report an issue: GitHub ↗.