siyuan-note/siyuan · error

323

323

Error message

Cannot disable encrypted notebooks: deleted-notebook history still depends on the current key backup. Clear that history first

What it means

Thrown by DisableEncryptedNotebook (crypto.go:1086, i18n code 323) when there are no live encrypted notebooks but the history directory still contains deleted encrypted-notebook snapshots. Those snapshots rely on the current MasterSalt/KEKVerifier (stored in the global key backup) to be restorable; disabling the feature would delete the backup and permanently lock the history. The user must clear that encrypted history first.

Source

Thrown at kernel/model/crypto.go:1086

	notebookCryptoMu.Lock()
	defer notebookCryptoMu.Unlock()

	// 检查是否还有加密笔记本(含 conf 损坏但存在备份的)
	ids, listErr := listAllEncryptedBoxIDs()
	if listErr != nil {
		return fmt.Errorf("list encrypted notebooks failed: %w", listErr)
	}
	if len(ids) > 0 {
		return errors.New("cannot disable encrypted notebook feature while encrypted notebooks exist, remove them first")
	}
	// 检查历史目录中是否存在已删除加密笔记本的历史快照:其恢复仍依赖当前 MasterSalt/KEKVerifier,
	// 删除备份前必须先清除这些历史(详见设计 §19)
	hasHistory, historyErr := scanEncryptedNotebookHistory()
	if historyErr != nil {
		return fmt.Errorf("check encrypted notebook history failed: %w", historyErr)
	}
	if hasHistory {
		return errors.New(Conf.Language(323))
	}

	Conf.m.Lock()
	Conf.NotebookCrypto.Enabled = false
	Conf.NotebookCrypto.MasterSalt = nil
	Conf.NotebookCrypto.KEKVerifier = nil
	Conf.NotebookCrypto.VerifierNonce = nil
	Conf.m.Unlock()

	Conf.Save()
	removeNotebookCryptoBackup() // 禁用时清理备份,避免残留旧密钥材料
	IncSync()
	return nil
}

// restoreNotebookCryptoConfigFromBackup 把备份里的 NotebookCrypto 配置装回本机 conf.json(不需主密码)。
// 用于数据同步/导入 Data.zip 后:备份文件随 DataDir 到达新设备,但本机 conf.json 的 NotebookCrypto 还是空的。
// 此时把 salt/verifier/KDFParams 装回并置 Enabled=true,让 UI 显示"已启用",笔记本显示为锁定(解锁仍需主密码)。

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Clear the encrypted-notebook history entries (delete the relevant snapshot directories under the history folder, or use the history-clear UI) and retry disable.
  2. If you want to keep the history restorable, do NOT disable; instead keep the feature enabled, or restore the deleted notebook and decrypt it to normal before disabling.
  3. After history is cleared, confirm scanEncryptedNotebookHistory returns false, then disable.
Defensive patterns

Strategy: validation

Validate before calling

// Before disable, confirm no encrypted-notebook history remains.
hasHist, err := model.HasEncryptedNotebookHistory()
if err != nil {
    return err
}
if hasHist {
    return errors.New("clear deleted encrypted-notebook history before disabling")
}

Try / catch

if err := model.DisableEncryptedNotebook(); err != nil {
    if err.Error() == model.Conf.Language(323) {
        respond(c, "clear deleted-notebook encrypted history first, then disable")
        return
    }
    respond(c, err.Error())
}

Prevention

When it happens

Trigger: POST /api/notebook/disableEncryptedNotebooks when listAllEncryptedBoxIDs is empty AND scanEncryptedNotebookHistory returns true. A history snapshot directory <HistoryDir>/<ts>-<op>/<boxID>/.siyuan/ contains notebook-crypto-backup.json or a conf.json with Encrypted=true.

Common situations: User deleted an encrypted notebook (its ciphertext moved into history), then tries to disable the feature without purging history. After sync, history snapshots of a deleted encrypted notebook arrived on a new device.

Related errors


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