siyuan-note/siyuan · error

Encrypted notebooks already exist but the master key backup

Error message

Encrypted notebooks already exist but the master key backup is missing. Restore the original conf.json or backup file to re-enable

What it means

ExportNotebookCryptoBackup fails when the on-disk notebook-crypto backup file does not exist (os.IsNotExist). The function copies the persisted backup (data-crypto-backup.json) into the export directory for user download; if there is no backup file to copy, it returns Conf.Language(315). This signals that encrypted notebooks exist or were expected, but the independent recovery backup is missing — a recovery-required state.

Source

Thrown at kernel/model/crypto.go:282

	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 251596fc0d)

Solutions

  1. Restore the original conf.json or a previously exported backup file to <DataDir>/.siyuan/data-crypto-backup.json, then retry export.
  2. If the master password is known and encryption is still enabled in conf.json, regenerate the backup via the re-enable/recovery path rather than exporting a non-existent one.
  3. Locate the backup from another synced device's DataDir and copy it into place.
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the backup file exists before offering export.
if !filelock.IsExist(filepath.Join(util.DataDir, ".siyuan", "data-crypto-backup.json")) {
    // do not offer 'export backup'; route user to recovery instead
}

Prevention

When it happens

Trigger: User invokes 'export key backup' from the encryption settings UI, but <DataDir>/.siyuan/data-crypto-backup.json is absent. Typical when conf.json still references encryption but the backup was manually deleted, an external sync deleted it, or a prior enable/write failed after partial cleanup.

Common situations: User deleted the .siyuan backup file manually; a broken sync removed the backup while leaving encrypted notebook data; conf.json restored from an old copy that points at encryption without a matching backup; filesystem cleanup tools removing hidden files.

Related errors


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