{"record":{"id":"485ea3644f66723a","repo":"siyuan-note/siyuan","slug":"panic-err-485ea3","errorCode":null,"errorMessage":"panic(err)","messagePattern":"panic\\(err\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/mobile/kernel.go","lineNumber":381,"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":363,"sourceCodeEnd":399,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/mobile/kernel.go#L363-L399","documentation":"The mobile (gomobile) export of kernel.Unzip panics when gulu.Zip.Unzip fails to extract a zip archive. Because gomobile bindings cannot return Go errors conveniently for this void API, failures are surfaced as a panic that the native side must catch. The underlying cause is logged before panicking.","triggerScenarios":"Calling Unzip(zipFilePath, destination) from the native (Android/iOS/HarmonyOS) side with a corrupt, missing, or password-protected zip, or a destination path that cannot be written.","commonSituations":"Interrupted downloads leaving truncated zip files, storage-permission denials on mobile, insufficient disk space, wrong path handling across platform file APIs.","solutions":["Verify the zip file exists and is fully downloaded before calling Unzip","Check/request storage permissions and confirm the destination directory is writable","Catch the panic/exception on the native side and surface a friendly error to the user","Re-download the archive if it is corrupt; verify size or checksum first"],"exampleFix":"// before (Java/Kotlin native side)\nUnzip(zipPath, dest)\n// after\ntry { Unzip(zipPath, dest) } catch (e: Throwable) { showError(\"Unzip failed: ${e.message}\") }","handlingStrategy":"try-catch","validationCode":"if (!fs.existsSync(zipPath) || fs.statSync(zipPath).size === 0) throw new Error('zip missing or empty');","typeGuard":null,"tryCatchPattern":"try { Unzip(zipPath, dest) } catch (t) { log(TAG, \"Unzip failed\", t); showUserError(t); }","preventionTips":["Verify download completeness (size/checksum) before unzipping","Ensure storage permissions and destination writability","Always wrap gomobile void APIs in native-side try/catch"],"tags":["mobile","gomobile","unzip","panic"],"backgroundTag":"panic-in-error-error","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}