router-for-me/CLIProxyAPI · error
zip entry %s uses backslash path separators
Error message
zip entry %s uses backslash path separators
What it means
Returned by cleanZipName (install.go:379-381) when an entry name contains a backslash. The zip spec mandates forward slashes; backslashes are ambiguous (a legal filename character on Unix, a separator on Windows) and are a classic zip-slip vector, so the store rejects them outright instead of guessing.
Source
Thrown at internal/pluginstore/install.go:380
return nil, 0, fmt.Errorf("read %s: %w", targetName, errRead)
}
mode := target.FileInfo().Mode().Perm()
if mode == 0 {
mode = 0o755
}
return data, mode, nil
}
func versionedPluginFileName(id string, version string, goos string) string {
return strings.TrimSpace(id) + "-v" + normalizeVersion(version) + pluginExtension(goos)
}
func cleanZipName(name string) (string, error) {
if strings.TrimSpace(name) == "" {
return "", fmt.Errorf("zip entry has empty name")
}
if strings.Contains(name, `\`) {
return "", fmt.Errorf("zip entry %s uses backslash path separators", name)
}
if path.IsAbs(name) {
return "", fmt.Errorf("zip entry %s is absolute", name)
}
cleaned := path.Clean(name)
if cleaned == "." || cleaned == ".." || strings.HasPrefix(cleaned, "../") {
return "", fmt.Errorf("zip entry %s escapes archive root", name)
}
return cleaned, nil
}
func regularZipFile(file *zip.File) bool {
mode := file.FileInfo().Mode()
return mode.IsRegular() || mode.Type() == 0
}
func hasDynamicLibraryExtension(name string) bool {
lowerName := strings.ToLower(name)View on GitHub (pinned to 78f0c4079e)
Solutions
- Rebuild the archive with forward-slash paths (e.g. use Go's archive/zip, Info-ZIP, or 'tar' equivalents)
- If stuck with the original producer, re-zip on a system that normalizes separators: unzip then zip fresh
- Fix the release pipeline to use a spec-compliant zip library
Example fix
# before (PowerShell, stores backslashes) Compress-Archive -Path bin\myplugin.dll -DestinationPath plugin.zip # after (forward slashes, spec compliant) zip plugin.zip bin/myplugin.dll
Defensive patterns
Strategy: validation
Validate before calling
func zipUsesForwardSlashes(archiveData []byte) error {
r, err := zip.NewReader(bytes.NewReader(archiveData), int64(len(archiveData)))
if err != nil { return err }
for _, f := range r.File {
if strings.Contains(f.Name, `\`) {
return fmt.Errorf("entry %q uses backslash separators", f.Name)
}
}
return nil
} Prevention
- Build release archives with spec-compliant tools (Info-ZIP, Go archive/zip) not path-naive Windows packers
- Add an archive lint (unzip -l / custom scan) to the release pipeline
- Prefer tar.gz or spec-correct zips consistently across platforms
When it happens
Trigger: InstallArchive on a zip written by a Windows tool that stored paths like 'bin\\myplugin.dll'. Any entry in the archive triggers it — the check runs for all entries before extension filtering, not just the target library.
Common situations: Artifacts zipped with PowerShell's Compress-Archive or .NET System.IO.Compression in some configurations; older Windows packers that stored native separators.
Related errors
- zip entry has empty name
- zip entry %s is absolute
- zip entry %s escapes archive root
- plugin_update_requires_restart
- zip entry %s is not a regular file
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/2b4f5d4f95f92b7f.
Report an issue: GitHub.