{"record":{"id":"2237d4f2100ab833","repo":"jeessy2/ddns-go","slug":"w-zip-v","errorCode":null,"errorMessage":"%w zip 文件: %v","messagePattern":"%w zip 文件: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/update/decompress.go","lineNumber":45,"sourceCode":"// 可能返回以下封装过的错误：\n//   - errCannotDecompressFile\n//   - errExecutableNotFoundInArchive\nfunc decompressCommand(src io.Reader, url, cmd string) (io.Reader, error) {\n\tfor ext, decompress := range fileTypes {\n\t\tif strings.HasSuffix(url, ext) {\n\t\t\treturn decompress(src, cmd)\n\t\t}\n\t}\n\tlog.Print(\"It's not a compressed file, skip decompressing\")\n\treturn src, nil\n}\n\nfunc unzip(src io.Reader, cmd string) (io.Reader, error) {\n\t// 解压 Zip 格式时需要文件大小。\n\t// 因此我们需要先将 HTTP 响应读取到缓冲区中。\n\tbuf, err := io.ReadAll(src)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w zip 文件: %v\", errCannotDecompressFile, err)\n\t}\n\n\tr := bytes.NewReader(buf)\n\tz, err := zip.NewReader(r, r.Size())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"%w zip 文件: %s\", errCannotDecompressFile, err)\n\t}\n\n\tfor _, file := range z.File {\n\t\t_, name := filepath.Split(file.Name)\n\t\tif !file.FileInfo().IsDir() && matchExecutableName(cmd, name) {\n\t\t\treturn file.Open()\n\t\t}\n\t}\n\n\treturn nil, fmt.Errorf(\"在 zip 文件中%w：%q\", errExecutableNotFoundInArchive, cmd)\n}\n","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/jeessy2/ddns-go/blob/5874c2e6667c69357ab95079421131104bd3fcae/util/update/decompress.go#L27-L63","documentation":"unzip must buffer the whole source into memory because zip decompression requires the file size; if io.ReadAll of the HTTP response (or other reader) fails, it returns errCannotDecompressFile wrapped with this message. The %w wrapping preserves the sentinel for errors.Is checks.","triggerScenarios":"Calling the update/self-update flow that downloads an archive and unzips it, when reading the response stream fails mid-download — network drop, connection reset, timeout, or a reader error on the underlying stream.","commonSituations":"Unstable network during self-update; proxy or firewall cutting long downloads; server closing connection early; running behind flaky VPN.","solutions":["Check network connectivity and retry the update command","Verify the download URL is reachable and the server keeps the connection open for large files","Retry with a more stable connection or smaller/resumable download; use errors.Is(err, errCannotDecompressFile) to confirm this family"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Verify the download source is reachable before streaming\nresp, err := http.Get(archiveURL)\nif err != nil {\n    return fmt.Errorf(\"archive unreachable: %w\", err)\n}\ndefer resp.Body.Close()\nif resp.ContentLength == 0 {\n    return fmt.Errorf(\"archive is empty\")\n}","typeGuard":null,"tryCatchPattern":"r, err := unzip(src, cmd)\nif err != nil {\n    if errors.Is(err, errCannotDecompressFile) {\n        // transient read failure: retry download with backoff\n        return retryDownload(archiveURL, cmd)\n    }\n    return err\n}","preventionTips":["Retry downloads on unstable networks with backoff","Check Content-Length before streaming to detect truncation","Avoid updating over flaky VPN/proxy connections","Use errors.Is(err, errCannotDecompressFile) to branch retry logic"],"tags":["zip","decompression","network","io"],"backgroundTag":"archive-decompression-failed","analyzedSha":"5874c2e6667c69357ab95079421131104bd3fcae","analyzedAt":"2026-09-03T15:41:16.799Z","contentChangedAt":"2026-09-03T15:41:16.799Z","schemaVersion":2},"datasetVersion":"2026-09-11T00:17:11.886Z"}