{"record":{"id":"965cebf8141de397","repo":"multica-ai/multica","slug":"read-zip-data-w","errorCode":null,"errorMessage":"read zip data: %w","messagePattern":"read zip data: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/internal/cli/update.go","lineNumber":516,"sourceCode":"\t\t}\n\t\t// Match the binary name (may be prefixed with a directory).\n\t\tif filepath.Base(hdr.Name) == name && hdr.Typeflag == tar.TypeReg {\n\t\t\tdata, err := io.ReadAll(tr)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"read binary: %w\", err)\n\t\t\t}\n\t\t\treturn data, nil\n\t\t}\n\t}\n}\n\n// extractBinaryFromZip reads a .zip stream and returns the contents of the\n// named file entry. The zip format requires random access, so the full archive\n// is buffered in memory.\nfunc extractBinaryFromZip(r io.Reader, name string) ([]byte, error) {\n\tbuf, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read zip data: %w\", err)\n\t}\n\n\tzr, err := zip.NewReader(bytes.NewReader(buf), int64(len(buf)))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"zip reader: %w\", err)\n\t}\n\n\tfor _, f := range zr.File {\n\t\tif filepath.Base(f.Name) == name && !f.FileInfo().IsDir() {\n\t\t\trc, err := f.Open()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"open zip entry: %w\", err)\n\t\t\t}\n\t\t\tdefer rc.Close()\n\n\t\t\tdata, err := io.ReadAll(rc)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"read binary: %w\", err)","sourceCodeStart":498,"sourceCodeEnd":534,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/cli/update.go#L498-L534","documentation":"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.","triggerScenarios":"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).","commonSituations":"Refactoring the updater to stream the zip instead of pre-buffering; tests feeding truncated readers; concurrent close of the underlying source.","solutions":["Ensure the reader passed in stays open and unmodified for the full duration of the call.","Pre-buffer the data yourself (io.ReadAll) and pass bytes.NewReader if the source is flaky or rate-limited.","Retry the read with a fresh reader — mid-stream failures from sockets are transient.","For OOM-adjacent failures, free memory or stream instead of buffering the whole archive."],"exampleFix":"// before\nrc, _ := http.Get(url)\ndata, err := extractBinaryFromZip(rc.Body, \"multica.exe\") // socket may reset mid-read\n\n// after\nrc, _ := http.Get(url)\nbuf, _ := io.ReadAll(rc.Body)\nrc.Body.Close()\ndata, err := extractBinaryFromZip(bytes.NewReader(buf), \"multica.exe\")","handlingStrategy":"validation","validationCode":"// pre-buffer flaky sources before calling extractBinaryFromZip\nbuf, err := io.ReadAll(src)\nif err != nil {\n    return err // handle source failure here, not inside extraction\n}\ndata, err := extractBinaryFromZip(bytes.NewReader(buf), \"multica.exe\")","typeGuard":null,"tryCatchPattern":"data, err := extractBinaryFromZip(r, \"multica.exe\")\nif err != nil && strings.HasPrefix(err.Error(), \"read zip data\") {\n    // source reader failed mid-buffer: retry with a fresh, fully-buffered reader\n}","preventionTips":["Pass bytes.NewReader over fully-read data, not live network readers","Keep the source reader open and untouched for the whole call","In the updater path this error is rare because bytes are pre-buffered and verified"],"tags":["zip","io","extraction","buffering"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}