siyuan-note/siyuan · error

no DEK cached for box " + boxID

Error message

no DEK cached for box " + boxID

What it means

GetDEK found no DEK cached for the given (valid, accessible) box ID. A DEK is only in cachedDEKs while the encrypted notebook is unlocked; for unencrypted boxes the DEK is populated when the notebook is loaded. Absence means the key was never loaded or was evicted/zeroed.

Solutions

  1. Ensure the notebook is loaded/unlocked (DEK populated) before calling GetDEK; verify the box ID spelling matches the loaded notebook
  2. Add retry/re-check after unlock completes rather than assuming the cache is warm
  3. If it happens at boot, move the work to after workspace/notebook initialization completes
Defensive patterns

Strategy: retry

Validate before calling

// ensure the notebook is loaded/unlocked first
if !boxLoaded(boxID) { return errors.New("load or unlock the notebook before requesting its DEK") }

Try / catch

dek, err := model.GetDEK(boxID); if err != nil && strings.Contains(err.Error(), "no DEK cached") { /* reload/unlock the notebook, then retry once */ }

Prevention

When it happens

Trigger: Calling GetDEK before the notebook's key-loading path ran (e.g. very early at boot), after LockEncryptedBox zeroed and removed the entry, after ChangeMasterPassword cleared caches, or with a box ID that has no loaded session.

Common situations: Race between a background worker and the user locking a notebook; calling encryption helpers from a plugin/API context without mounting the notebook; startup ordering issues.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/442d86f3e97e4184. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/crypto.go:1684

		panic("extract encryption nonce failed: " + err.Error())
	}
	return nonce
}

// GetDEK 取已缓存的 DEK。返回副本,避免外部零化影响缓存。
// filesys/assets/db 加解密时调用。
func GetDEK(boxID string) ([]byte, error) {
	if !ast.IsNodeIDPattern(boxID) {
		return nil, errors.New("invalid notebook ID")
	}
	if IsEncryptedBox(boxID) && !isBoxUnlockedForAccess(boxID) {
		return nil, errors.New("encrypted notebook is not accessible")
	}
	cachedDEKsLock.RLock()
	defer cachedDEKsLock.RUnlock()
	dek, ok := cachedDEKs[boxID]
	if !ok {
		return nil, errors.New("no DEK cached for box " + boxID)
	}
	ret := make([]byte, len(dek))
	copy(ret, dek)
	return ret, nil
}

// ClearDEK 清除指定笔记本的 DEK。Unmount 单个加密笔记本时调用。
func ClearDEK(boxID string) {
	LockBox(boxID)
}

// ChangeMasterPassword 改主密码:用旧密码校验后,用新密码派生新 KEK,
// 重新加密 verifier,并把所有加密笔记本的 WrappedDEK 用新 KEK 重新包络后写回各自的 BoxConf。
//
// 使用两阶段提交确保崩溃后可恢复:
//
//	Phase 0: 预计算所有新 WrappedDEK(内存)
//	Phase 1: 写入 migration manifest

View on GitHub (pinned to 9f775e8a12)