siyuan-note/siyuan · critical

unzip [%s] failed: %s

Error message

unzip [%s] failed: %s

What it means

Logged via logging.LogErrorf and then re-panicked by the mobile kernel's Unzip helper when gulu.Zip.Unzip fails to extract zipFilePath into destination. This is a gomobile-exported function called from native Android/iOS/HarmonyOS code; because gomobile bindings cannot return Go errors ergonomically, the helper panics after logging so the native layer receives a recoverable crash. The %s in the log line interpolates the underlying error.

Source

Thrown at kernel/mobile/kernel.go:371

	return filepath.Base(path)
}

func FilterUploadFileName(name string) string {
	return util.FilterUploadFileName(name)
}

func AssetName(name string) string {
	return util.AssetName(name, ast.NewNodeID())
}

func HTML2Markdown(html string) string {
	return util.NewLute().HTML2Md(html)
}

func Unzip(zipFilePath, destination string) {
	if err := gulu.Zip.Unzip(zipFilePath, destination); nil != err {
		logging.LogErrorf("unzip [%s] failed: %s", zipFilePath, err)
		panic(err)
	}
}

// GetExportFilePath 解析导出文件绝对路径,绕过 HTTP 层以避免锁屏密码拦截。
// exportPath 格式为 "/export/xxx.zip" 或 "assets/xxx"。
// 返回文件在磁盘上的绝对路径,以便原生端分块拷贝,避免大文件内存溢出。
// 解析失败返回空字符串。
func GetExportFilePath(exportPath string) (ret string) {
	var absPath string
	if after, ok := strings.CutPrefix(exportPath, "/export/"); ok {
		fileName := after
		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]", exportPath, fileName)
			return

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Verify zipFilePath exists and is readable before calling Unzip; ensure the download completed (check size/checksum).
  2. Create the destination directory (os.MkdirAll) with appropriate permissions before calling Unzip.
  3. Confirm the process has write permission to destination (especially on Android scoped storage).
  4. If the file may be corrupt, re-download it; validate with a zip integrity check before invoking Unzip.

Example fix

// before (native side): unzip whatever path was passed
kernel.Unzip(zipPath, dest)
// after: native side pre-checks, and kernel helper could be wrapped
// In Go, if you control the call site, prefer returning an error instead of panicking:
func Unzip(zipFilePath, destination string) error {
  if err := os.MkdirAll(destination, 0755); err != nil { return err }
  return gulu.Zip.Unzip(zipFilePath, destination)
}
Defensive patterns

Strategy: try-catch

Validate before calling

if _, err := os.Stat(zipFilePath); err != nil { return err }
if err := os.MkdirAll(destination, 0755); err != nil { return err }

Try / catch

defer func() {
    if r := recover(); r != nil {
        // log r, surface a user-facing error, keep the app alive
    }
}()
kernel.Unzip(zipPath, dest)

Prevention

When it happens

Trigger: Native code calls kernel.Unzip with a path that does not exist, is not a valid zip, is corrupted/truncated, or whose destination is not writable / does not exist / is on a protected storage path.

Common situations: Downloading a marketplace package (theme/icon/template/plugin) whose download was truncated; a destination directory that was not created first; permission denied on external storage; a file that is a zip64 archive the unzip lib cannot handle; disk full mid-extraction.

Related errors


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