golang/go · error
invalid file name: %v
Error message
invalid file name: %v
What it means
Returned by (*zip.openDir).ReadDir (reader.go:981) as an fs.PathError when a directory entry inside the zip has a name that is '.', '..', empty, contains a slash (i.e., is not a single path element), or otherwise fails fs.ValidPath. The zip reader exposes archives as an fs.FS and must guarantee each entry name is a valid path element.
Source
Thrown at src/archive/zip/reader.go:981
if count > 0 && n > count {
n = count
}
if n == 0 {
if count <= 0 {
return nil, nil
}
return nil, io.EOF
}
list := make([]fs.DirEntry, n)
for i := range list {
s, err := d.files[d.offset+i].stat()
if err != nil {
return nil, err
} else if s.Name() == "." || !fs.ValidPath(s.Name()) {
return nil, &fs.PathError{
Op: "readdir",
Path: d.e.name,
Err: fmt.Errorf("invalid file name: %v", d.files[d.offset+i].name),
}
}
list[i] = s
}
d.offset += n
return list, nil
}
View on GitHub (pinned to b6b368adc5)
Solutions
- Re-create the zip with unix-style relative single-element names per entry (no leading '/', no '\', no '.'/'..' segments).
- If you must read a non-conforming zip, use zip.OpenReader and iterate FileHeader slices directly instead of the fs.FS interface.
- Sanitize entry names before re-archiving: filepath.ToSlash + filepath.Clean, refuse absolute paths.
- Validate with fs.ValidPath before adding entries when producing zips.
Example fix
// before
zfs, _ := zip.OpenReader("win.zip")
fs.WalkDir(zfs, ".", ...) // -> invalid file name on '\' entries
// after
zr, _ := zip.OpenReader("win.zip")
for _, f := range zr.File {
name := path.Clean(filepath.ToSlash(f.Name)) // normalize manually
... // process via f.Open() directly
} Defensive patterns
Strategy: validation
Validate before calling
// Validate entry names before exposing a zip as fs.FS.
func zipEntryNamesValid(zr *zip.ReadCloser) error {
for _, f := range zr.File {
name := filepath.ToSlash(f.Name)
if !fs.ValidPath(name) && name != "/" {
return fmt.Errorf("invalid entry name %q", f.Name)
}
}
return nil
} Type guard
func validZipEntryName(name string) bool {
return fs.ValidPath(filepath.ToSlash(name))
} Prevention
- Produce zips with unix-style relative single-element names per entry.
- For non-conforming zips, iterate FileHeader slices directly instead of using fs.FS.
- Sanitize with filepath.ToSlash + path.Clean and reject absolute paths before re-archiving.
When it happens
Trigger: Calling ReadDir (via fs.ReadDir on a zip-opened directory, or fs.WalkDir over a zip fs.FS) on a zip whose entries contain backslashes (Windows paths), absolute paths, leading '/', '.', '..', or empty names. Such entries are valid in raw zip but invalid as fs.FS nodes.
Common situations: Zips produced by Windows archivers using '\' separators; archives with absolute entry names like '/etc/passwd'; entries named '.' or containing '..' segments; zips crafted with malicious path components (zip-slip style); mixing directory and file separators.
Related errors
- missing top-level directory prefix
- zip file contains more than one top-level directory
- decompressor already registered
- compressor already registered
- zip: SetOffset called after data was written
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/ad867ed28f2eefe8.
Report an issue: GitHub.