siyuan-note/siyuan · error

Conf.Language(310)

Error message

Conf.Language(310)

What it means

deriveNotebookCryptoBackupCandidate throws Conf.Language(310) when the synchronized notebook-crypto backup file cannot be loaded or is incomplete (missing MasterSalt or KEKVerifier). Without a valid backup there is no salt to derive the KEK from and no verifier to check the password against, so unlock/restore from backup is impossible. It means 'no usable encrypted-notebook crypto backup found'.

Source

Thrown at kernel/model/crypto.go:1194

	*Conf.NotebookCrypto = *backup
	Conf.m.Unlock()
	Conf.Save()
	// 恢复成功后同步重写备份,确保配置和备份内容一致。
	// 调用方已持有 notebookCryptoMu,且 writeNotebookCryptoBackupData 不再申请该锁,故无死锁;
	// 同步写避免与 ChangeMasterPassword 的并发备份写竞争同一文件(lost update 导致 verifier 被回退)。
	nc := *backup
	if err := writeNotebookCryptoBackupData(&nc, kek); err != nil {
		logging.LogWarnf("rewrite notebook crypto backup after restore failed: %s", err)
	}
	logging.LogInfof("notebook crypto restored from backup (e.g. after sync to a new device)")
	return kek, nil
}

// deriveNotebookCryptoBackupCandidate 对同步备份做无副作用验证,并确认它覆盖全部现有加密笔记本。
func deriveNotebookCryptoBackupCandidate(password string) (backup *conf.NotebookCrypto, kek []byte, err error) {
	backup, err = loadNotebookCryptoBackup()
	if err != nil || backup == nil || len(backup.MasterSalt) == 0 || len(backup.KEKVerifier) == 0 {
		return nil, nil, errors.New(Conf.Language(310))
	}
	params, validErr := util.ValidateArgon2Params(backup.KDFParams)
	if validErr != nil {
		return nil, nil, errors.New(Conf.Language(317))
	}
	kek = util.DeriveKey(password, backup.MasterSalt, params)
	decrypted, decryptErr := util.DecryptWithAAD(kek, backup.KEKVerifier, []byte("siyuan:kek-verifier"))
	if decryptErr != nil || string(decrypted) != string(kekVerifierMagic) {
		zeroAndClear(kek)
		return nil, nil, errors.New(Conf.Language(311))
	}
	if backup.Spec != conf.CurrentNotebookCryptoSpec || backup.Checksum == "" ||
		len(backup.KEKMAC) == 0 || !verifyKEKMAC(backup, kek) {
		zeroAndClear(kek)
		return nil, nil, errors.New(Conf.Language(316))
	}
	if !verifyKEKAgainstExistingBoxes(kek, backup) || !verifyKEKAgainstEncryptedHistory(kek, backup) {
		zeroAndClear(kek)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Ensure the notebook-crypto backup file exists in the workspace Data directory (re-sync from a device where the feature is enabled) and retry the unlock
  2. Restore the conf.json NotebookCrypto section from the original device (or full workspace backup) instead of relying on the backup file
  3. If the data genuinely has no crypto backup and history snapshots were also deleted, the encrypted content cannot be unlocked — restore from a full backup that includes both Data and the crypto backup
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check that the crypto backup is loadable and complete before attempting unlock/restore
backup, err := model.LoadNotebookCryptoBackup()
if err != nil || backup == nil || len(backup.MasterSalt) == 0 || len(backup.KEKVerifier) == 0 {
    return errors.New("no usable notebook-crypto backup in Data dir; re-sync from the source device first")
}

Try / catch

// Caller pattern
kek, err := deriveKEK(password)
if errors.Is(err, errNoUsableBackup) { // Language(310)
    // prompt user to re-sync Data (including the crypto backup file) and retry
}

Prevention

When it happens

Trigger: Calling tryRestoreNotebookCryptoFromBackupLocked or deriveKEK on a device where Conf.NotebookCrypto.Enabled is false and loadNotebookCryptoBackup() returns an error, nil, or a backup with empty MasterSalt/KEKVerifier — e.g. unlocking an encrypted notebook right after data was synced/imported to a new device without the backup file.

Common situations: Syncing or importing Data to a new machine where the crypto backup file was excluded or not yet synced; a corrupted/empty backup file; user attempting to unlock an encrypted notebook on a device that never had the crypto config.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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