{"record":{"id":"f85b6bc23e28fa77","repo":"flipped-aurora/gin-vue-admin","slug":"w-f85b6b","errorCode":null,"errorMessage":"解压技能包失败: %w","messagePattern":"解压技能包失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_skills.go","lineNumber":461,"sourceCode":"\tif zipResp.StatusCode != http.StatusOK {\n\t\treturn fmt.Errorf(\"下载压缩包失败, HTTP状态码: %d\", zipResp.StatusCode)\n\t}\n\n\ttmpFile, err := os.CreateTemp(\"\", \"gva-skill-*.zip\")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"创建临时文件失败: %w\", err)\n\t}\n\ttmpPath := tmpFile.Name()\n\tdefer os.Remove(tmpPath)\n\n\tif _, err = io.Copy(tmpFile, zipResp.Body); err != nil {\n\t\ttmpFile.Close()\n\t\treturn fmt.Errorf(\"保存技能包失败: %w\", err)\n\t}\n\ttmpFile.Close()\n\n\tif err = extractZipToDir(tmpPath, skillsDir); err != nil {\n\t\treturn fmt.Errorf(\"解压技能包失败: %w\", err)\n\t}\n\n\treturn nil\n}\n\nfunc extractZipToDir(zipPath, destDir string) error {\n\tr, err := zip.OpenReader(zipPath)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer r.Close()\n\n\tfor _, f := range r.File {\n\t\tname := filepath.FromSlash(f.Name)\n\t\tif strings.Contains(name, \"..\") {\n\t\t\tcontinue\n\t\t}\n","sourceCodeStart":443,"sourceCodeEnd":479,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_skills.go#L443-L479","documentation":"This error wraps a failure from extractZipToDir when unzipping a downloaded skill package into the skills directory. It occurs after the zip was successfully saved to a temp file, so the cause is either a corrupt/invalid zip archive or filesystem errors creating/writing files under skillsDir. The wrapped %w error carries the underlying reason.","triggerScenarios":"Calling DownloadOnlineSkill when extractZipToDir(tmpPath, skillsDir) fails: the downloaded file is not a valid zip (truncated download, HTML error page saved as zip), zip-slip or entry-extraction errors, or write/permission errors creating the target skill directory.","commonSituations":"Remote server returning a 4xx/5xx HTML page that gets saved and then fails unzip; interrupted download producing a truncated archive; skillsDir owned by another user or read-only volume; zip entries with illegal paths rejected by the extractor.","solutions":["Re-download the skill package and confirm the URL serves a valid zip (check HTTP status and Content-Type before extraction)","Check permissions/ownership of the skills target directory and free disk space","Validate the temp file is a zip (e.g. zip.OpenReader) before extracting to give a clearer message","Inspect the wrapped cause in logs to see whether it is archive corruption or filesystem failure"],"exampleFix":"// before\nzipResp := download(url)\nio.Copy(tmpFile, zipResp.Body)\nextractZipToDir(tmpPath, skillsDir)\n// after\nif zipResp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"下载失败，状态码: %d\", zipResp.StatusCode)\n}\nif _, err := zip.OpenReader(tmpPath); err != nil {\n    return fmt.Errorf(\"下载内容不是有效 zip 包: %w\", err)\n}\nextractZipToDir(tmpPath, skillsDir)","handlingStrategy":"validation","validationCode":"// Go: verify it is a valid zip before extracting\nif _, err := zip.OpenReader(tmpPath); err != nil {\n    return fmt.Errorf(\"下载的文件不是有效的 zip 包: %w\", err)\n}\nif st, err := os.Stat(destDir); err != nil || !st.IsDir() {\n    return fmt.Errorf(\"目标目录不可写\")\n}","typeGuard":"// Go: check archive validity\nfunc isZipFile(path string) bool {\n    r, err := zip.OpenReader(path)\n    if err != nil {\n        return false\n    }\n    defer r.Close()\n    return true\n}","tryCatchPattern":"err := svc.DownloadOnlineSkill(name)\nif err != nil {\n    var zerr *zip.Error\n    if errors.As(err, &zerr) {\n        // corrupt archive: re-download the package\n    }\n    log.Errorf(\"解压技能包失败: %v\", err)\n}","preventionTips":["Check HTTP status/Content-Type before saving the body","Validate the archive (zip.OpenReader) before extraction","Ensure the skills directory exists and is writable at startup","Delete partial temp files on failure to avoid stale corrupt archives"],"tags":["zip","filesystem","go"],"backgroundTag":"zip-extraction-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}