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
- 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
- Restore the conf.json NotebookCrypto section from the original device (or full workspace backup) instead of relying on the backup file
- 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
- Always sync/import the complete Data directory, including the notebook-crypto backup file
- After moving to a new device, confirm the backup file exists before unlocking encrypted notebooks
- Keep an offline copy of the workspace that includes the crypto backup
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
- Conf.Language(323)
- %w: %v (errMasterPasswordMigrationPending)
- master password migration is pending
- Please unlock the encrypted notebook first
- Please unlock the encrypted notebook first
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/94b8e9a4c879e896.
Report an issue: GitHub.