siyuan-note/siyuan · error

Conf.Language(315)

Error message

Conf.Language(315)

What it means

ExportNotebookCryptoBackup() copies the global key backup file (<DataDir>/.siyuan/data-crypto-backup.json) into the export directory. If reading it fails with os.IsNotExist, it returns Conf.Language(315): 'Encrypted notebooks already exist but the master key backup is missing. Restore the original conf.json or backup file to re-enable'. The backup holds the MasterSalt/verifier chain; without it a lost conf.json makes existing WrappedDEK undecryptable even with the correct password.

Source

Thrown at kernel/model/crypto.go:283

	tmpPath := path + "." + gulu.Rand.String(7) + ".tmp"
	if err := os.WriteFile(tmpPath, data, 0644); err != nil {
		return err
	}
	return os.Rename(tmpPath, path)
}

// ExportNotebookCryptoBackup 把密钥备份文件复制到 export 目录,返回可下载的相对路径。
// 供用户主动导出保存,作为同步之外的独立恢复途径(详见设计文档 §4.1)。
// 备份文件本身不含主密码(salt 不保密、verifier 是密文),拿到它也解不开任何数据。
func ExportNotebookCryptoBackup() (downloadPath string, err error) {
	notebookCryptoMu.Lock()
	defer notebookCryptoMu.Unlock()

	backupPath := dataCryptoBackupPath()
	data, readErr := filelock.ReadFile(backupPath)
	if readErr != nil {
		if os.IsNotExist(readErr) {
			err = errors.New(Conf.Language(315))
			return
		}
		err = readErr
		return
	}
	exportBase := filepath.Join(util.TempDir, "export")
	if mkErr := os.MkdirAll(exportBase, 0755); mkErr != nil {
		err = mkErr
		return
	}
	// 用随机名避免不同用户/设备互相覆盖,文件名固定带易识别前缀
	fileName := "notebook-crypto-backup-" + gulu.Rand.String(7) + ".json"
	downloadPath = "/export/" + url.PathEscape(fileName)
	if writeErr := os.WriteFile(filepath.Join(exportBase, fileName), data, 0644); writeErr != nil {
		err = writeErr
		return
	}
	return

View on GitHub (pinned to afa823b6b4)

Solutions

  1. Restore data-crypto-backup.json from dejavu sync history or any file-level backup of the workspace
  2. Alternatively restore the original conf.json that matched the current encrypted notebooks, as the message states
  3. Verify the file exists at <workspace>/data/.siyuan/data-crypto-backup.json and retry the export
  4. After recovery, export the backup immediately and store it outside the workspace
Defensive patterns

Strategy: validation

Validate before calling

backupPath := filepath.Join(util.DataDir, ".siyuan", "data-crypto-backup.json")
if !filelock.IsExist(backupPath) {
    return errors.New("no key backup present - nothing to export")
}

Prevention

When it happens

Trigger: Invoking the export while the backup file was never written (enablement interrupted), deleted by the user or an over-eager cleaner, or excluded/removed by a sync tool that does not carry the .siyuan directory.

Common situations: Selective sync (Dropbox/own scripts) skipping dot-directories; restore of conf.json from a snapshot predating encryption enablement; antivirus/cleaner removing unknown .json files.

Related errors


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