{"record":{"id":"686a640a602da1b4","repo":"siyuan-note/siyuan","slug":"unzip-s-failed","errorCode":null,"errorMessage":"unzip [%s] failed","messagePattern":"unzip \\[(.+?)\\] failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/harmony/kernel.go","lineNumber":247,"sourceCode":"\treturn C.CString(util.FilterUploadFileName(C.GoString(name)))\n}\n\n//export AssetName\nfunc AssetName(name *C.char) *C.char {\n\treturn C.CString(util.AssetName(C.GoString(name), ast.NewNodeID()))\n}\n\n//export HTML2Markdown\nfunc HTML2Markdown(html *C.char) *C.char {\n\treturn C.CString(util.NewLute().HTML2Md(C.GoString(html)))\n}\n\n//export Unzip\nfunc Unzip(zipFilePath, destination *C.char) {\n\tvar zipPath string = C.GoString(zipFilePath)\n\tif err := gulu.Zip.Unzip(zipPath, C.GoString(destination)); nil != err {\n\t\tlogging.LogErrorf(\"unzip [%s] failed: %s\", zipPath, err)\n\t\tpanic(err)\n\t}\n}\n\n//export GetExportFilePath\nfunc GetExportFilePath(exportPath *C.char) *C.char {\n\tpathStr := C.GoString(exportPath)\n\tvar absPath string\n\tif strings.HasPrefix(pathStr, \"/export/\") {\n\t\tfileName := strings.TrimPrefix(pathStr, \"/export/\")\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]\", pathStr, fileName)\n\t\t\treturn nil\n\t\t}\n\t\t// 加密导出需要持有覆盖原生复制过程的租约，旧路径解析接口不再返回其明文地址。","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/harmony/kernel.go#L229-L265","documentation":"The HarmonyOS (gomobile) exported Unzip binding extracts a zip archive via gulu.Zip.Unzip and panics on any failure — the message \"unzip [%s] failed\" reflects a logged error followed by a panic that crosses the JNI boundary. Any invalid archive, bad destination path, or I/O error aborts the whole call.","triggerScenarios":"Calling the mobile binding Unzip(zipFilePath, destination) with a corrupt/truncated zip, a nonexistent zip path, an unwritable destination, or an archive containing unsafe entries that gulu.Zip.Unzip rejects.","commonSituations":"On-device package import (templates/plugins) where the downloaded asset is incomplete, storage is full, or the destination directory lacks write permission.","solutions":["Verify the zip file exists and is complete (re-download the asset).","Ensure the destination directory exists and the app has write access and free space.","Catch the panic/error at the native (ArkTS/Java) boundary and surface a user-facing message instead of crashing."],"exampleFix":"// before: Unzip(zipPath, dest) panics on corrupt archive\n// after: check archive integrity first\nif (!fileExists(zipPath) || !isValidZip(zipPath)) { showToast(\"invalid package\"); return; }\nUnzip(zipPath, dest)","handlingStrategy":"try-catch","validationCode":"// native side, before calling Unzip\nif (!fs.existsSync(zipPath) || fileSize(zipPath) === 0) { showToast(\"package missing\"); return; }","typeGuard":null,"tryCatchPattern":"try {\n  kernel.Unzip(zipPath, destPath)\n} catch (e) {\n  showToast(`unzip failed: ${e.message}`)\n}","preventionTips":["Verify download completeness (size/hash) before extraction","Ensure the destination directory exists and is writable","Never assume Unzip returns normally — it panics on failure in the gomobile binding"],"tags":["harmony","zip","panic"],"backgroundTag":"file-read-failed","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}