siyuan-note/siyuan · error
no encrypted key material for box [%s]
Error message
no encrypted key material for box [%s]
What it means
decryptBoxCrypt in kernel/model/crypto.go throws this when the notebook's BoxEncryption config is missing, nil, or has an empty WrappedDEK field. The WrappedDEK is the envelope-encrypted data encryption key; without it there is no key material to unwrap with the KEK, so decryption cannot even be attempted. This is a configuration/state problem, not a wrong-password problem.
Source
Thrown at kernel/model/crypto.go:1324
return nil, errMasterPasswordMigrationPending
}
if err = saveNotebookCryptoBackup(kek); err != nil {
zeroAndClear(kek)
return nil, fmt.Errorf("%w: %v", errMasterPasswordMigrationPending, err)
}
removeMasterPasswordMigration()
}
return kek, nil
}
// decryptBoxCrypt 用 KEK 解密 box 的 WrappedDEK。优先使用 GetBoxEncryption 的结果(conf → backup fallback),
// 若解密失败则尝试 backup 中不同的 WrappedDEK。
// 返回解密后的 DEK 和实际使用的 BoxCrypt(可能来自 backup)。
// 若 backup 被使用会自动修复 conf.json 和刷新 backup。
func decryptBoxCrypt(boxID string, kek []byte) (dek []byte, boxCrypt *conf.BoxEncryption, err error) {
boxCrypt, err = GetBoxEncryption(boxID)
if err != nil || boxCrypt == nil || len(boxCrypt.WrappedDEK) == 0 {
return nil, nil, fmt.Errorf("no encrypted key material for box [%s]", boxID)
}
nc := currentNotebookCrypto()
dek, err = decryptWrappedDEKWithHistory(boxID, boxCrypt, kek, nc)
if err == nil {
return dek, boxCrypt, nil
}
// 主 BoxCrypt 无法解密:尝试 backup 中不同的 WrappedDEK
backup, bErr := readNotebookCryptBackup(boxID)
if bErr == nil && backup != nil && len(backup.WrappedDEK) > 0 &&
!bytes.Equal(backup.WrappedDEK, boxCrypt.WrappedDEK) {
dek, err = decryptWrappedDEKWithHistory(boxID, backup, kek, nc)
if err == nil {
// backup 解密成功:修复 conf + 刷新 backup
box := &Box{ID: boxID}
boxConf := box.GetConf()
boxConf.Encrypted = trueView on GitHub (pinned to 8641553a1f)
Solutions
- Verify the notebook is actually encrypted and that conf.json contains a BoxEncryption object with a non-empty WrappedDEK
- If conf.json is corrupted or stale, restore it from a trusted sync/backup snapshot rather than recreating the notebook
- If the notebook should not be encrypted, stop calling the unlock/change-password API on it and check encryption state first
- Re-enable notebook encryption through the UI so a fresh key envelope is generated, then retry unlock
Example fix
// before
boxCrypt, _ := GetBoxEncryption(boxID)
dek, _, err := decryptBoxCrypt(boxID, kek)
// after
boxCrypt, err := GetBoxEncryption(boxID)
if err != nil || boxCrypt == nil || len(boxCrypt.WrappedDEK) == 0 {
return fmt.Errorf("box [%s] has no encrypted key envelope; check conf.json or enable encryption", boxID)
}
dek, _, err := decryptBoxCrypt(boxID, kek) Defensive patterns
Strategy: validation
Validate before calling
// Go
crypt, err := model.GetBoxEncryption(boxID)
if err != nil || crypt == nil || len(crypt.WrappedDEK) == 0 {
return fmt.Errorf("box %s has no key envelope; skipping unlock", boxID)
}
// then call the unlock path Type guard
func hasKeyEnvelope(c *conf.BoxEncryption) bool {
return c != nil && len(c.WrappedDEK) > 0
} Prevention
- Never hand-edit conf.json; let the kernel write BoxEncryption
- Include conf.json (with envelope) in workspace backups and verify restores
- Check notebook encryption state before calling unlock APIs
When it happens
Trigger: GetBoxEncryption(boxID) returns an error, a nil boxCrypt, or a boxCrypt with len(WrappedDEK)==0. Reached via UnlockBox -> unlockBoxHeld, ChangeMasterPassword, or the recovery test path when the box has no stored encrypted key envelope.
Common situations: conf.json was manually edited or truncated and lost the BoxCrypt section; the notebook was created before encryption was enabled so no envelope exists; a sync/backup restored an older conf.json; the box ID passed does not correspond to an encrypted notebook.
Related errors
- no encrypted key material for box
- Conf.Language(26)
- Conf.Language(26)
- symlink resolves into encrypted notebook [%s]
- master password migration is pending
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/d0182522d76487cf.
Report an issue: GitHub.