router-for-me/CLIProxyAPI · error
open zip: %w
Error message
open zip: %w
What it means
Wrapped error from InstallArchive when zip.NewReader fails on the provided archiveData, meaning the bytes are not a valid ZIP archive (bad magic, truncated file, corruption). The library opens the archive fully in memory (bytes.NewReader over the whole slice) before extracting the plugin library, so any parse failure aborts before touching the filesystem.
Source
Thrown at internal/pluginstore/install.go:256
return plugin, nil
}
return Plugin{}, fmt.Errorf("direct install plugin %q version %q not found in source", id, version)
}
func InstallArchive(archiveData []byte, plugin Plugin, options InstallOptions) (InstallResult, error) {
options = normalizeInstallOptions(options)
id := strings.TrimSpace(plugin.ID)
if !validPluginID(id) {
return InstallResult{}, fmt.Errorf("invalid plugin id %q", plugin.ID)
}
version := normalizeVersion(plugin.Version)
if !validPluginVersion(version) {
return InstallResult{}, fmt.Errorf("invalid plugin version %q", plugin.Version)
}
plugin.Version = version
reader, errZip := zip.NewReader(bytes.NewReader(archiveData), int64(len(archiveData)))
if errZip != nil {
return InstallResult{}, fmt.Errorf("open zip: %w", errZip)
}
libraryData, mode, errLibrary := readTargetLibrary(reader, id, version, options.GOOS)
if errLibrary != nil {
return InstallResult{}, errLibrary
}
targetPath, errTarget := installTargetPath(options, id, version)
if errTarget != nil {
return InstallResult{}, errTarget
}
overwritten := false
if _, errStat := os.Stat(targetPath); errStat == nil {
overwritten = true
} else if !errors.Is(errStat, os.ErrNotExist) {
return InstallResult{}, fmt.Errorf("stat target plugin: %w", errStat)
}
if overwritten {View on GitHub (pinned to 78f0c4079e)
Solutions
- Verify the bytes are a ZIP before calling: check the 'PK\x03\x04' magic or open with archive/zip yourself
- Confirm the download actually retrieved the artifact (HTTP status, Content-Type, length) and wasn't an error page
- If corruption is possible in transit/storage, run checksum verification before install
Example fix
// before
data, _ := os.ReadFile("plugin.tar.gz") // wrong format
res, err := pluginstore.InstallArchive(data, plugin, options)
// after
data, err := os.ReadFile("plugin.zip")
if err != nil { return err }
if _, err := zip.NewReader(bytes.NewReader(data), int64(len(data))); err != nil {
return fmt.Errorf("not a valid zip archive: %w", err)
}
res, err := pluginstore.InstallArchive(data, plugin, options) Defensive patterns
Strategy: validation
Validate before calling
func isZip(data []byte) bool {
return len(data) > 4 && string(data[:4]) == "PK\x03\x04"
}
func preflightArchive(data []byte) error {
if !isZip(data) {
return errors.New("artifact is not a zip archive")
}
if _, err := zip.NewReader(bytes.NewReader(data), int64(len(data))); err != nil {
return fmt.Errorf("zip parse failed: %w", err)
}
return nil
} Type guard
func isZipOpenError(err error) bool {
return err != nil && strings.Contains(err.Error(), "open zip:")
} Try / catch
if _, err := pluginstore.InstallArchive(data, plugin, options); err != nil {
if isZipOpenError(err) {
var formatErr zip.FormatError
if errors.As(err, &formatErr) {
return errors.New("corrupt or non-zip artifact; re-download and verify checksum")
}
}
} Prevention
- Always verify checksums on downloaded artifacts before install
- Check HTTP status and Content-Type when fetching artifacts to catch error pages
- Preflight the zip magic bytes in your download pipeline
When it happens
Trigger: Passing bytes that are not a ZIP: a tarball (.tar.gz), a raw .so/.dylib file, an HTML error page saved as the 'artifact', a truncated download, or a corrupted buffer.
Common situations: Download pipeline that forgot to decompress/repackage, or fetched the wrong content type; disk-full corruption of a cached artifact; double-gzip; upstream serving a redirect body instead of following it; checksum verification skipped so corruption went unnoticed earlier.
Related errors
- direct install plugin %q version %q: %w
- zip entry %s is not a regular file
- target dynamic library must be at zip root
- dynamic library filename must be %s or %s
- weight must not exceed %d
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/dd8f562111a72fd6.
Report an issue: GitHub.