siyuan-note/siyuan · error

panic(err)

Error message

panic(err)

What it means

The gomobile-exported Unzip binding panics when gulu.Zip.Unzip fails to extract an archive. On mobile, panics crossing the JNI/ObjC bridge surface as crashes of the host app; the error is logged first, then re-raised with panic(err). It means the zip file could not be opened or extracted (missing file, corrupt archive, bad destination path, or insufficient space/permissions).

Source

Thrown at kernel/harmony/kernel.go:247

	return C.CString(util.FilterUploadFileName(C.GoString(name)))
}

//export AssetName
func AssetName(name *C.char) *C.char {
	return C.CString(util.AssetName(C.GoString(name), ast.NewNodeID()))
}

//export HTML2Markdown
func HTML2Markdown(html *C.char) *C.char {
	return C.CString(util.NewLute().HTML2Md(C.GoString(html)))
}

//export Unzip
func Unzip(zipFilePath, destination *C.char) {
	var zipPath string = C.GoString(zipFilePath)
	if err := gulu.Zip.Unzip(zipPath, C.GoString(destination)); nil != err {
		logging.LogErrorf("unzip [%s] failed: %s", zipPath, err)
		panic(err)
	}
}

//export GetExportFilePath
func GetExportFilePath(exportPath *C.char) *C.char {
	pathStr := C.GoString(exportPath)
	var absPath string
	if strings.HasPrefix(pathStr, "/export/") {
		fileName := strings.TrimPrefix(pathStr, "/export/")
		if decoded, err := url.PathUnescape(fileName); err == nil {
			fileName = decoded
		}
		fileName = filepath.Clean(fileName)
		if strings.HasPrefix(fileName, "..") {
			logging.LogWarnf("get export file path [%s] blocked: path traversal attempt [%s]", pathStr, fileName)
			return nil
		}
		// 加密导出需要持有覆盖原生复制过程的租约,旧路径解析接口不再返回其明文地址。

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Check the kernel log for 'unzip [...] failed' to see the underlying cause (open error, crc, mkdir failure).
  2. Verify the zip file exists and is fully downloaded (compare file size/checksum) before calling Unzip.
  3. Pass absolute paths for both zipFilePath and destination and ensure the destination directory exists and is writable.
  4. On the native side, wrap the binding call so a panic does not crash the app; pre-validate inputs instead of relying on the binding.
  5. Free device storage if the error indicates write failures.

Example fix

// before: calling with an unverified path
bridge.Unzip(zipPath, destDir) // panics if zip is corrupt
// after: validate on the native side first
if (!fileExists(zipPath)) throw new Error("zip file missing: " + zipPath);
try { bridge.Unzip(zipPath, destDir); } catch (e) { showError("unzip failed: " + e); }
Defensive patterns

Strategy: try-catch

Validate before calling

if (!fs.existsSync(zipPath)) throw new Error("zip missing: " + zipPath);
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
if (fs.statSync(zipPath).size === 0) throw new Error("zip is empty: " + zipPath);

Try / catch

try {
  window.siyuan.bridge.Unzip(zipPath, destDir);
} catch (e) {
  console.error("unzip failed:", e); // binding panicked; do not let it crash the app
  showDialog({ content: "Unzip failed, check the archive and destination path" });
}

Prevention

When it happens

Trigger: Calling the exported Unzip(zipFilePath, destination) from Android/iOS/HarmonyOS bindings with a nonexistent or unreadable zip path, a corrupted archive, an unwritable destination, or a destination path that already blocks extraction.

Common situations: Importing a .sy.zip or asset package where the download was incomplete; requesting extraction into a path without write permission; storage full on device; passing a relative path instead of an absolute one.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/d07519c795c7768d. Report an issue: GitHub.