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
}
returnView on GitHub (pinned to afa823b6b4)
Solutions
- Restore data-crypto-backup.json from dejavu sync history or any file-level backup of the workspace
- Alternatively restore the original conf.json that matched the current encrypted notebooks, as the message states
- Verify the file exists at <workspace>/data/.siyuan/data-crypto-backup.json and retry the export
- 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
- Ensure sync tooling includes the data/.siyuan directory - the backup lives there
- Export and store the key backup off-workspace immediately after enabling encryption
- Watch for NotebookCryptoStateRecoveryRequired states - they precede this failure
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.