siyuan-note/siyuan · critical
encrypted notebook has no valid key material
Error message
encrypted notebook has no valid key material
What it means
Thrown by GetBoxEncryption when the notebook is identified as encrypted (conf.json marks it Encrypted=true, or IsEncryptedBox detects encryption markers) but no usable key material exists: conf.json's BoxCrypt is nil/empty AND the per-notebook crypt backup is missing or has no WrappedDEK. This is a data-loss condition — the notebook is encrypted but its key is unrecoverable from any local source.
Source
Thrown at kernel/model/crypto.go:1921
// conf 中有完整的 BoxCrypt
if confMarkedEncrypted && boxConf.BoxCrypt != nil && len(boxConf.BoxCrypt.WrappedDEK) > 0 {
return boxConf.BoxCrypt, nil
}
// fallback 到 backup
backup, err := readNotebookCryptBackup(boxID)
if err != nil {
return nil, err
}
if backup != nil && len(backup.WrappedDEK) > 0 {
markRuntimeEncryptedBox(boxID)
return backup, nil
}
// backup 也不可用
if confMarkedEncrypted || IsEncryptedBox(boxID) {
// conf 标记为加密但密钥材料缺失 → 明确错误(而非误报"未加密")
return nil, errors.New("encrypted notebook has no valid key material")
}
return nil, nil // 真正的非加密笔记本
}
// needWriteNotebookCryptBackup 检查是否需要写入/刷新 per-notebook backup。
// backup 不存在、或内容与 crypt 不一致时返回 true。
func needWriteNotebookCryptBackup(boxID string, crypt *conf.BoxEncryption) bool {
existing, err := readNotebookCryptBackup(boxID)
if err != nil || existing == nil {
return true
}
return !bytes.Equal(existing.WrappedDEK, crypt.WrappedDEK) ||
!bytes.Equal(existing.WrapNonce, crypt.WrapNonce) ||
!bytes.Equal(existing.Metadata, crypt.Metadata) ||
existing.Spec != crypt.Spec ||
existing.CreatedAt != crypt.CreatedAt
}
View on GitHub (pinned to 251596fc0d)
Solutions
- Restore from a DataDir backup that contains a valid conf.json with BoxCrypt or a per-notebook crypt backup for this notebook.
- If sync is enabled, wait for a sync from another device that has the valid key material (both conf and backup sync with the workspace).
- If a master-password migration manifest exists, restart SiYuan — recoverMasterPasswordMigration may rebuild BoxCrypt from the manifest's NewWrappedDEK.
- If no key material exists anywhere, the notebook's encrypted content (.sy files, assets, AV data) is permanently unrecoverable.
Defensive patterns
Strategy: try-catch
Validate before calling
// Check key material availability before unlocking:
boxCrypt, err := model.GetBoxEncryption(boxID)
if err != nil {
// if err is 'encrypted notebook has no valid key material',
// the notebook is unrecoverable without a backup
return
}
if boxCrypt == nil {
// not encrypted — no unlock needed
return
} Try / catch
boxCrypt, err := model.GetBoxEncryption(boxID)
if err != nil {
if strings.Contains(err.Error(), "no valid key material") {
// critical: key material is lost
// advise user to restore from DataDir backup or sync from another device
}
return
} Prevention
- Keep regular DataDir backups that include both conf.json and per-notebook crypt backups.
- Enable sync so key material propagates to at least one other device.
- Never delete the .siyuan/conf.json or backup files from an encrypted notebook directory.
- Resolve sync conflicts by keeping the complete BoxCrypt from one device.
When it happens
Trigger: Called via the API layer (api/notebook.go:654) during unlock, or from ChangeMasterPassword. Fires when conf.json has Encrypted=true but BoxCrypt was deleted/corrupted, and the backup file is also gone. IsEncryptedBox may detect encryption through ciphertext signatures in the notebook data even when conf is damaged.
Common situations: conf.json was manually edited and the BoxCrypt section was deleted. A sync conflict dropped both conf BoxCrypt and the backup. The notebook directory was partially copied/restored without the .siyuan/conf.json or backup files. A disk failure corrupted both key sources. The notebook was imported without its key material.
Related errors
- no encrypted key material for box
- path belongs to encrypted notebook [%s]: %s
- 315
- unsupported encrypted notebook key envelope
- encrypted notebook key envelope creation time is missing
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/17dd0b0fefe6fade.
Report an issue: GitHub.