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

  1. Re-create the zip with unix-style relative single-element names per entry (no leading '/', no '\', no '.'/'..' segments).
  2. If you must read a non-conforming zip, use zip.OpenReader and iterate FileHeader slices directly instead of the fs.FS interface.
  3. Sanitize entry names before re-archiving: filepath.ToSlash + filepath.Clean, refuse absolute paths.
  4. 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

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


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/ad867ed28f2eefe8. Report an issue: GitHub.