siyuan-note/siyuan · critical
no encrypted key material for box
Error message
no encrypted key material for box
What it means
Thrown by unlockBoxHeld (crypto.go:1375) when the provided boxEnc is nil or its WrappedDEK is empty, meaning there is no encrypted key material to unwrap a DEK from. The function sets the box state to EncryptedBoxStateError and returns, so the notebook is flagged as broken rather than silently treated as unlocked/unencrypted. This usually indicates the notebook's encryption metadata (conf BoxCrypt or the per-notebook backup) is missing or was wiped.
Source
Thrown at kernel/model/crypto.go:1375
wasUnlocked := IsBoxUnlocked(boxID)
if err = unlockBoxHeld(boxID, password, boxEnc); err != nil {
return false, err
}
alreadyMount, err = mountBox(boxID)
if err != nil && !wasUnlocked {
lockBoxWithPreparationHeld(boxID, nil)
}
return alreadyMount, err
}
func unlockBoxHeld(boxID string, password string, boxEnc *conf.BoxEncryption) (err error) {
if _, busy := boxLock.Load(boxID); busy {
return errors.New(Conf.language(239))
}
if boxEnc == nil || len(boxEnc.WrappedDEK) == 0 {
setEncryptedBoxState(boxID, EncryptedBoxStateError)
return errors.New("no encrypted key material for box")
}
if IsBoxUnlocked(boxID) {
if GetEncryptedBoxState(boxID) == EncryptedBoxStateError {
return errors.New(Conf.Language(316))
}
setEncryptedBoxState(boxID, EncryptedBoxStateUnlocked)
return nil
}
setEncryptedBoxState(boxID, EncryptedBoxStateUnlocking)
// 获取 box 写锁,与 LockBox/unmount0 串行化,防止并发锁/解锁导致 db/DEK 状态不一致
acquireBoxWriteLock(boxID)
finalState := EncryptedBoxStateLocked
defer func() {
releaseBoxWriteLock(boxID)
setEncryptedBoxState(boxID, finalState)
}()
View on GitHub (pinned to 251596fc0d)
Solutions
- Restore the notebook's BoxCrypt (WrappedDEK) from its per-notebook key backup or from conf.json backup, then retry.
- If the key material is unrecoverable and the data is expendable, remove the notebook and recreate it.
- Do not call unlockBoxHeld with a nil boxEnc; fetch it via GetBoxEncryption and handle nil at the call site.
Example fix
// before
model.UnlockBox(boxID, password, nil)
// after
boxCrypt, err := model.GetBoxEncryption(boxID)
if err != nil || boxCrypt == nil || len(boxCrypt.WrappedDEK) == 0 {
return fmt.Errorf("no key material for notebook %s", boxID)
}
model.UnlockBox(boxID, password, boxCrypt) Defensive patterns
Strategy: validation
Validate before calling
// Ensure key material exists before unlocking.
boxCrypt, err := model.GetBoxEncryption(boxID)
if err != nil {
return fmt.Errorf("cannot read encryption metadata: %w", err)
}
if boxCrypt == nil || len(boxCrypt.WrappedDEK) == 0 {
return fmt.Errorf("no encrypted key material for notebook %s; restore its backup", boxID)
}
model.UnlockBox(boxID, password, boxCrypt) Type guard
func hasWrappedDEK(b *conf.BoxEncryption) bool { return b != nil && len(b.WrappedDEK) > 0 } Try / catch
if err := model.UnlockBox(boxID, password, boxCrypt); err != nil {
if err.Error() == "no encrypted key material for box" {
respond(c, "notebook key material missing; restore the notebook backup or remove the notebook")
return
}
respond(c, err.Error())
} Prevention
- Always fetch boxEnc via GetBoxEncryption and check for nil/empty before calling UnlockBox.
- Keep per-notebook key backups intact so WrappedDEK can be restored.
- Do not partially delete a notebook directory (it can leave Encrypted=true with no key material).
When it happens
Trigger: UnlockBox/UnlockAndMountBox called with a boxEnc that GetBoxEncryption returned as nil or with empty WrappedDEK. Note the HTTP handler checks this earlier (returns 319), so reaching here means a direct Go caller passed a nil/empty boxEnc, or the box's conf and backup both lack WrappedDEK.
Common situations: Notebook conf.json lost its BoxCrypt field (corruption/bad sync) and no per-notebook backup exists. Caller passed nil explicitly. Notebook directory partially deleted, leaving Encrypted=true but no key material.
Related errors
- 315
- encrypted notebook has no valid key material
- enable encrypted notebook failed: failed to persist key back
- cannot disable encrypted notebook feature while encrypted no
- 323
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/ecab7b95d651445b.
Report an issue: GitHub.