{"record":{"id":"a79466e34d42c4cc","repo":"siyuan-note/siyuan","slug":"unzip-s-failed-s","errorCode":null,"errorMessage":"unzip [%s] failed: %s","messagePattern":"unzip \\[(.+?)\\] failed: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"kernel/mobile/kernel.go","lineNumber":371,"sourceCode":"\treturn filepath.Base(path)\n}\n\nfunc FilterUploadFileName(name string) string {\n\treturn util.FilterUploadFileName(name)\n}\n\nfunc AssetName(name string) string {\n\treturn util.AssetName(name, ast.NewNodeID())\n}\n\nfunc HTML2Markdown(html string) string {\n\treturn util.NewLute().HTML2Md(html)\n}\n\nfunc Unzip(zipFilePath, destination string) {\n\tif err := gulu.Zip.Unzip(zipFilePath, destination); nil != err {\n\t\tlogging.LogErrorf(\"unzip [%s] failed: %s\", zipFilePath, err)\n\t\tpanic(err)\n\t}\n}\n\n// GetExportFilePath 解析导出文件绝对路径，绕过 HTTP 层以避免锁屏密码拦截。\n// exportPath 格式为 \"/export/xxx.zip\" 或 \"assets/xxx\"。\n// 返回文件在磁盘上的绝对路径，以便原生端分块拷贝，避免大文件内存溢出。\n// 解析失败返回空字符串。\nfunc GetExportFilePath(exportPath string) (ret string) {\n\tvar absPath string\n\tif after, ok := strings.CutPrefix(exportPath, \"/export/\"); ok {\n\t\tfileName := after\n\t\tif decoded, err := url.PathUnescape(fileName); err == nil {\n\t\t\tfileName = decoded\n\t\t}\n\t\tfileName = filepath.Clean(fileName)\n\t\tif strings.HasPrefix(fileName, \"..\") {\n\t\t\tlogging.LogWarnf(\"get export file path [%s] blocked: path traversal attempt [%s]\", exportPath, fileName)\n\t\t\treturn","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/mobile/kernel.go#L353-L389","documentation":"Logged via logging.LogErrorf and then re-panicked by the mobile kernel's Unzip helper when gulu.Zip.Unzip fails to extract zipFilePath into destination. This is a gomobile-exported function called from native Android/iOS/HarmonyOS code; because gomobile bindings cannot return Go errors ergonomically, the helper panics after logging so the native layer receives a recoverable crash. The %s in the log line interpolates the underlying error.","triggerScenarios":"Native code calls kernel.Unzip with a path that does not exist, is not a valid zip, is corrupted/truncated, or whose destination is not writable / does not exist / is on a protected storage path.","commonSituations":"Downloading a marketplace package (theme/icon/template/plugin) whose download was truncated; a destination directory that was not created first; permission denied on external storage; a file that is a zip64 archive the unzip lib cannot handle; disk full mid-extraction.","solutions":["Verify zipFilePath exists and is readable before calling Unzip; ensure the download completed (check size/checksum).","Create the destination directory (os.MkdirAll) with appropriate permissions before calling Unzip.","Confirm the process has write permission to destination (especially on Android scoped storage).","If the file may be corrupt, re-download it; validate with a zip integrity check before invoking Unzip."],"exampleFix":"// before (native side): unzip whatever path was passed\nkernel.Unzip(zipPath, dest)\n// after: native side pre-checks, and kernel helper could be wrapped\n// In Go, if you control the call site, prefer returning an error instead of panicking:\nfunc Unzip(zipFilePath, destination string) error {\n  if err := os.MkdirAll(destination, 0755); err != nil { return err }\n  return gulu.Zip.Unzip(zipFilePath, destination)\n}","handlingStrategy":"try-catch","validationCode":"if _, err := os.Stat(zipFilePath); err != nil { return err }\nif err := os.MkdirAll(destination, 0755); err != nil { return err }","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        // log r, surface a user-facing error, keep the app alive\n    }\n}()\nkernel.Unzip(zipPath, dest)","preventionTips":["Pre-create and permission the destination directory before unzipping.","Verify the archive integrity (size, CRC) after download and before extraction.","On native platforms, wrap Unzip calls in recover to convert panics into recoverable errors."],"tags":["mobile","gomobile","filesystem","zip","panic","archive"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}