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

  1. Verify the bytes are a ZIP before calling: check the 'PK\x03\x04' magic or open with archive/zip yourself
  2. Confirm the download actually retrieved the artifact (HTTP status, Content-Type, length) and wasn't an error page
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/dd8f562111a72fd6. Report an issue: GitHub.