siyuan-note/siyuan · error

cannot save incomplete notebook crypto configuration

Error message

cannot save incomplete notebook crypto configuration

What it means

saveNotebookCryptoBackup refuses to persist a notebook crypto configuration that fails notebookCryptoConfigurationComplete. Before writing the backup file, it copies Conf.NotebookCrypto, runs prepareBackupForWrite, and recomputes KEKMAC from the supplied KEK; if the resulting configuration is still incomplete (missing Spec, BackupID, CreatedAt, Checksum, or KEKMAC), it aborts so an unusable backup is never written to disk and Conf is never left pointing at a partial state. This is an internal invariant guard required because restoring from an incomplete backup would break authenticated access to encrypted notebooks.

Source

Thrown at kernel/model/crypto.go:390

	return nil
}

// saveNotebookCryptoBackup 把当前 NotebookCrypto(含 MasterSalt/KEKVerifier/KDFParams)备份到 DataDir。
// kek 必须非 nil:在 Checksum 定型后计算 KEKMAC 并落盘,保证恢复路径可通过 MAC 校验。
// 无 KEK 生成的备份 KEKMAC 必为空,会被 deriveKEK/恢复路径拒绝,等于制造无法解锁的状态(详见设计 §19)。
func saveNotebookCryptoBackup(kek []byte) error {
	if kek == nil {
		// 无 KEK 时不得生成当前格式备份:KEKMAC 缺失会被 deriveKEK/恢复路径拒绝,
		// 生成即等于制造无法解锁的状态。
		return errors.New("cannot generate notebook crypto backup without KEK")
	}
	Conf.m.Lock()
	nc := *Conf.NotebookCrypto // 值拷贝
	prepareBackupForWrite(&nc)
	nc.KEKMAC = computeKEKMAC(&nc, kek)
	if !notebookCryptoConfigurationComplete(&nc) {
		Conf.m.Unlock()
		return errors.New("cannot save incomplete notebook crypto configuration")
	}
	Conf.NotebookCrypto.Spec = nc.Spec
	Conf.NotebookCrypto.BackupID = nc.BackupID
	Conf.NotebookCrypto.CreatedAt = nc.CreatedAt
	Conf.NotebookCrypto.Checksum = nc.Checksum
	Conf.NotebookCrypto.KEKMAC = nc.KEKMAC // 保持 Conf 与备份文件的 KEKMAC 一致
	Conf.m.Unlock()
	backupPath := dataCryptoBackupPath()
	if err := os.MkdirAll(filepath.Dir(backupPath), 0755); err != nil {
		return fmt.Errorf("mkdir notebook crypto backup dir failed: %w", err)
	}
	data, err := json.Marshal(nc)
	if err != nil {
		return fmt.Errorf("marshal notebook crypto backup failed: %w", err)
	}
	if err := atomicWriteFile(backupPath, data); err != nil {
		return fmt.Errorf("write notebook crypto backup failed: %w", err)
	}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Recreate the configuration via EnableEncryptedNotebook so Spec, BackupID, CreatedAt, Checksum, and KEKMAC are all populated before saving
  2. Inspect Conf.NotebookCrypto (conf.json) to find which required field is empty and restore it from the existing backup file at the data crypto backup path
  3. If recovery material exists, use ImportNotebookCryptoBackup to load a complete backup instead of re-saving the incomplete in-memory config

Example fix

// before: re-saving a half-migrated Conf.NotebookCrypto
err := saveNotebookCryptoBackup(kek)
// after: only re-save when the config is complete
if notebookCryptoConfigurationComplete(&Conf.NotebookCrypto) {
    err = saveNotebookCryptoBackup(kek)
} else {
    err = restoreFromBackupOrReenable(kek)
}
Defensive patterns

Strategy: validation

Validate before calling

if !notebookCryptoConfigurationComplete(&Conf.NotebookCrypto) {
    // repair via backup import or re-run EnableEncryptedNotebook before saving
}

Prevention

When it happens

Trigger: Calling EnableEncryptedNotebook, deriveKEK, or ChangeMasterPassword when Conf.NotebookCrypto is missing required fields (empty Spec or BackupID, zero CreatedAt, or empty Checksum) so that even after prepareBackupForWrite and KEKMAC recomputation the configuration is still incomplete.

Common situations: Upgrading from a workspace whose conf.json predates the notebook-crypto feature and lacks the NotebookCrypto section; a corrupted or hand-edited conf.json with dropped fields; a bug or interrupted operation that wiped fields from Conf.NotebookCrypto before a KEK re-derivation was attempted.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/00465dfc7c20c322. Report an issue: GitHub.