siyuan-note/siyuan · error

Export failed

Error message

Export failed: %s

What it means

Thrown by the exportData helper behind model.ExportData (POST /api/export/exportData, i.e. Settings - Export - Export Data). The kernel first duplicates the entire <workspace>/data directory into <TempDir>/export/<workspace>-<timestamp> via filelock.Copy; if that copy fails, the raw OS error is wrapped into the localized template "Export failed: %s" (Conf.Language(14)) and the export aborts before any zip is created. The real cause (disk full, permission denied, locked file) is the wrapped text, also logged as "copy data dir from [...] to [...] failed".

Solutions

  1. Read the kernel log line "copy data dir from [...] to [...] failed: ..." — the suffix names the offending file and errno
  2. Free space on the volume hosting the kernel temp dir; the full data tree is duplicated uncompressed before zipping
  3. Close other SiYuan instances, sync and backup tools; exclude workspace and temp dirs from real-time antivirus scanning
  4. Verify the kernel process can read <workspace>/data and write <TempDir>/export (ownership, read-only flags)
  5. Retry the export once transient locks and space issues are cleared
Defensive patterns

Strategy: try-catch

Validate before calling

dataDir := filepath.Join(util.WorkspaceDir, "data")
if info, err := os.Stat(dataDir); err != nil || !info.IsDir() {
	return fmt.Errorf("data dir not readable: %w", err)
}
probe := filepath.Join(util.TempDir, "export", ".probe")
if err := os.WriteFile(probe, nil, 0600); err != nil {
	return fmt.Errorf("export temp dir not writable: %w", err)
}
os.Remove(probe)

Try / catch

zipPath, err := model.ExportData()
if err != nil {
	// err.Error() == "Export failed: <cause>" — surface the inner cause, do not retry blindly
	logging.LogErrorf("export data failed: %s", err)
	return
}

Prevention

When it happens

Trigger: POST /api/export/exportData when filelock.Copy cannot duplicate <WorkspaceDir>/data into the temp export folder: destination volume full (data is copied uncompressed before zipping), permission denied on files/subdirs, a data file held open by another process, or the workspace on an unavailable network drive.

Common situations: Large workspaces on a nearly full temp volume; antivirus or backup software locking .sy/asset files on Windows; a second SiYuan instance or sync job holding file locks; data dir made read-only or owned by another user.

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/2e6bccc6cb504021. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/export.go:752

	zipPath = "/export/" + url.PathEscape(filepath.Base(zipPath))
	return
}

func exportData(exportFolder string) (zipPath string, err error) {
	FlushTxQueue()

	logging.LogInfof("exporting data...")

	baseFolderName := "data-" + util.CurrentTimeSecondsStr()
	if err = os.MkdirAll(exportFolder, 0755); err != nil {
		logging.LogErrorf("create export temp folder failed: %s", err)
		return
	}

	data := filepath.Join(util.WorkspaceDir, "data")
	if err = filelock.Copy(data, exportFolder); err != nil {
		logging.LogErrorf("copy data dir from [%s] to [%s] failed: %s", data, baseFolderName, err)
		err = fmt.Errorf(Conf.Language(14), err.Error())
		return
	}

	zipPath = exportFolder + ".zip"
	zip, err := gulu.Zip.Create(zipPath)
	if err != nil {
		logging.LogErrorf("create export data zip [%s] failed: %s", exportFolder, err)
		return
	}

	zipCallback := func(filename string) {
		util.PushEndlessProgress(Conf.language(65) + " " + fmt.Sprintf(Conf.language(253), filename))
	}

	if err = zip.AddDirectory(baseFolderName, exportFolder, zipCallback); err != nil {
		logging.LogErrorf("create export data zip [%s] failed: %s", exportFolder, err)
		return
	}

View on GitHub (pinned to afa823b6b4)