multica-ai/multica · error

read zip data: %w

Error message

read zip data: %w

What it means

extractBinaryFromZip first buffers the entire stream with io.ReadAll; failure returns 'read zip data: %w'. The reader comes from a bytes.NewReader over already-verified bytes in the update path, so in production this error is rare and usually surfaces when the function is reused with a different io.Reader (network, file) that fails mid-read.

Source

Thrown at server/internal/cli/update.go:516

		}
		// Match the binary name (may be prefixed with a directory).
		if filepath.Base(hdr.Name) == name && hdr.Typeflag == tar.TypeReg {
			data, err := io.ReadAll(tr)
			if err != nil {
				return nil, fmt.Errorf("read binary: %w", err)
			}
			return data, nil
		}
	}
}

// extractBinaryFromZip reads a .zip stream and returns the contents of the
// named file entry. The zip format requires random access, so the full archive
// is buffered in memory.
func extractBinaryFromZip(r io.Reader, name string) ([]byte, error) {
	buf, err := io.ReadAll(r)
	if err != nil {
		return nil, fmt.Errorf("read zip data: %w", err)
	}

	zr, err := zip.NewReader(bytes.NewReader(buf), int64(len(buf)))
	if err != nil {
		return nil, fmt.Errorf("zip reader: %w", err)
	}

	for _, f := range zr.File {
		if filepath.Base(f.Name) == name && !f.FileInfo().IsDir() {
			rc, err := f.Open()
			if err != nil {
				return nil, fmt.Errorf("open zip entry: %w", err)
			}
			defer rc.Close()

			data, err := io.ReadAll(rc)
			if err != nil {
				return nil, fmt.Errorf("read binary: %w", err)

View on GitHub (pinned to 2c0912b6ec)

Solutions

  1. Ensure the reader passed in stays open and unmodified for the full duration of the call.
  2. Pre-buffer the data yourself (io.ReadAll) and pass bytes.NewReader if the source is flaky or rate-limited.
  3. Retry the read with a fresh reader — mid-stream failures from sockets are transient.
  4. For OOM-adjacent failures, free memory or stream instead of buffering the whole archive.

Example fix

// before
rc, _ := http.Get(url)
data, err := extractBinaryFromZip(rc.Body, "multica.exe") // socket may reset mid-read

// after
rc, _ := http.Get(url)
buf, _ := io.ReadAll(rc.Body)
rc.Body.Close()
data, err := extractBinaryFromZip(bytes.NewReader(buf), "multica.exe")
Defensive patterns

Strategy: validation

Validate before calling

// pre-buffer flaky sources before calling extractBinaryFromZip
buf, err := io.ReadAll(src)
if err != nil {
    return err // handle source failure here, not inside extraction
}
data, err := extractBinaryFromZip(bytes.NewReader(buf), "multica.exe")

Try / catch

data, err := extractBinaryFromZip(r, "multica.exe")
if err != nil && strings.HasPrefix(err.Error(), "read zip data") {
    // source reader failed mid-buffer: retry with a fresh, fully-buffered reader
}

Prevention

When it happens

Trigger: Calling extractBinaryFromZip directly with a network reader that times out or resets; a file handle closed concurrently; memory exhaustion during buffering of a very large stream (allocation failure surfaces as a read/panic path).

Common situations: Refactoring the updater to stream the zip instead of pre-buffering; tests feeding truncated readers; concurrent close of the underlying source.

Related errors


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/965cebf8141de397. Report an issue: GitHub.