siyuan-note/siyuan · error

unzip [ ] failed

Error message

unzip [%s] failed

What it means

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.

Solutions

  1. Verify the zip file exists and is complete (re-download the asset).
  2. Ensure the destination directory exists and the app has write access and free space.
  3. Catch the panic/error at the native (ArkTS/Java) boundary and surface a user-facing message instead of crashing.

Example fix

// before: Unzip(zipPath, dest) panics on corrupt archive
// after: check archive integrity first
if (!fileExists(zipPath) || !isValidZip(zipPath)) { showToast("invalid package"); return; }
Unzip(zipPath, dest)
Defensive patterns

Strategy: try-catch

Validate before calling

// native side, before calling Unzip
if (!fs.existsSync(zipPath) || fileSize(zipPath) === 0) { showToast("package missing"); return; }

Try / catch

try {
  kernel.Unzip(zipPath, destPath)
} catch (e) {
  showToast(`unzip failed: ${e.message}`)
}

Prevention

When it happens

Trigger: 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.

Common situations: On-device package import (templates/plugins) where the downloaded asset is incomplete, storage is full, or the destination directory lacks write permission.

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@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/686a640a602da1b4. Report an issue: GitHub.

Appendix: 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 9f775e8a12)