{"record":{"id":"764b6ce9fcabb83e","repo":"flipped-aurora/gin-vue-admin","slug":"w-764b6c","errorCode":null,"errorMessage":"保存技能包失败: %w","messagePattern":"保存技能包失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/service/system/sys_skills.go","lineNumber":456,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"下载压缩包失败: %w\", err)\n\t}\n\tdefer zipResp.Body.Close()\n\n\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 {","sourceCodeStart":438,"sourceCodeEnd":474,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/service/system/sys_skills.go#L438-L474","documentation":"This error wraps a failure to persist the downloaded online skill package (zip) to a temporary file on disk during DownloadOnlineSkill. The io.Copy call streams the HTTP response body into tmpFile; any read error from the network stream or write error to the local filesystem is wrapped with this message. It is a disk/IO failure, not a validation failure.","triggerScenarios":"Calling DownloadOnlineSkill when the HTTP response body of the skill package download cannot be fully read (connection dropped mid-transfer) or when writing to the temp file fails (disk full, permission denied on os.TempDir, tmpFile already closed).","commonSituations":"Unstable network/proxy interrupting the download of the skill zip; insufficient disk space in the temp directory; restricted tmp permissions in containerized deployments; read-only filesystem after a disk remount.","solutions":["Check free disk space on the partition backing os.TempDir (or TMPDIR) and clean up if full","Verify network connectivity/proxy stability to the skill download host and retry the download","Ensure the process has write permission to the temp directory in your deployment environment","Inspect the wrapped cause (%w) in logs to distinguish network read errors from file write errors"],"exampleFix":"// before\nif _, err = io.Copy(tmpFile, zipResp.Body); err != nil {\n    tmpFile.Close()\n    return fmt.Errorf(\"保存技能包失败: %w\", err)\n}\n// after\nif _, err = io.Copy(tmpFile, zipResp.Body); err != nil {\n    tmpFile.Close()\n    if netErr, ok := err.(net.Error); ok {\n        return fmt.Errorf(\"下载网络中断，请重试: %w\", netErr)\n    }\n    return fmt.Errorf(\"保存技能包失败: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// Go: preflight checks before download\nif st, err := os.Stat(os.TempDir()); err != nil || !st.IsDir() {\n    return fmt.Errorf(\"临时目录不可用\")\n}\nif avail := diskFree(os.TempDir()); avail < minNeededBytes {\n    return fmt.Errorf(\"临时目录空间不足\")\n}","typeGuard":"// Go: classify the wrapped error\nfunc isNetErr(err error) bool {\n    var ne net.Error\n    return errors.As(err, &ne)\n}\nfunc isPathErr(err error) bool {\n    var pe *fs.PathError\n    return errors.As(err, &pe)\n}","tryCatchPattern":"err := svc.DownloadOnlineSkill(name)\nif err != nil {\n    var pathErr *fs.PathError\n    if errors.As(err, &pathErr) && os.IsPermission(pathErr) {\n        // fix temp-dir permissions and retry\n    } else if errors.Is(err, syscall.ENOSPC) {\n        // free disk space and retry\n    }\n    log.Errorf(\"下载技能包失败: %v\", err)\n}","preventionTips":["Monitor temp-dir disk usage and alert before full","Set TMPDIR to a writable volume in containers","Retry downloads with backoff on transient network errors","Log the unwrapped cause so network vs. disk errors are distinguishable"],"tags":["filesystem","io","network","go"],"backgroundTag":"temp-file-write-failed","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}