siyuan-note/siyuan · critical

panic: gulu.Zip.Unzip error (dynamic message from err)

Error message

panic: gulu.Zip.Unzip error (dynamic message from err)

What it means

The HarmonyOS gomobile export `Unzip` calls `gulu.Zip.Unzip(zipPath, destination)` and, on any non-nil error, calls `panic(err)` after logging. Because exported gomobile functions cannot return Go errors to the native side, the implementation converts failure into a panic that crashes the Harmony runtime. The panic message is dynamic — it is whatever `err` from `gulu.Zip.Unzip` contained.

Source

Thrown at kernel/harmony/kernel.go:241

	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 251596fc0d)

Solutions

  1. Verify the source zip exists and is a valid archive before calling `Unzip` from the native side.
  2. Ensure the destination directory is created and writable by the app sandbox.
  3. Wrap the native call in a Harmony-level try/catch and surface a user-visible error instead of crashing.
  4. Pre-validate with a lightweight zip-header check to avoid triggering the panic.

Example fix

// Native caller (ArkTS/Java side) must guard, since Go side panics:
try {
  Unzip(zipPath, destPath)
} catch (e) {
  // show error to user; do not crash the UI
}
Defensive patterns

Strategy: try-catch

Validate before calling

// On the native side, validate inputs before calling the Go export:
if (!fs.existsSync(zipPath) || !fs.existsSync(destDir)) {
  throw new Error('zip source or destination missing')
}

Try / catch

// Harmony/ArkTS caller must catch the Go panic surfaced as an exception:
try {
  Unzip(zipPath, destPath)
} catch (e) {
  // log and present a user-facing error; keep the app alive
  logger.error(`unzip failed: ${e}`)
}

Prevention

When it happens

Trigger: The zip path does not exist, is not a valid zip, is unreadable, the destination directory does not exist or is unwritable, or the archive is corrupt. Any of these makes `gulu.Zip.Unzip` return an error, which is then panicked.

Common situations: Importing a downloaded template/plugin pack that failed to fully download; unzipping into a sandboxed Harmony path without permission; a truncated asset archive shipped with an update.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/129b2c99836172b3. Report an issue: GitHub.