siyuan-note/siyuan · error
encrypted notebook is locked, please unlock it first
Error message
encrypted notebook is locked, please unlock it first
What it means
Returned by GetDEKIfUnlocked when the box is recognized as encrypted but isBoxUnlockedForAccess returns false — meaning the notebook is in a locked state (auto-locked by idle timeout, manually locked via LockBox, or freshly started app with no DEK in memory). This is the fail-closed path from issue #18034: the function refuses to hand out a DEK so filesys will not silently write plaintext to an encrypted notebook.
Source
Thrown at kernel/model/crypto.go:2093
func IsEncryptedAssetPath(absPath string) bool {
boxID := ExtractBoxIDFromAssetsPath(absPath)
return boxID != "" && IsEncryptedBox(boxID)
}
// GetDEKIfUnlocked 返回已解锁加密笔记本的 DEK(副本)。
// 非加密笔记本返回 (nil, nil)——filesys 据此原样读写,对普通笔记本透明。
// 加密但未解锁(DEK 不在内存)返回 (nil, error)——filesys 的加解密函数遇 error 后拒绝读写,
// 避免加密笔记本在未解锁状态下静默以明文落盘(深度防御,见 issue #18034)。
func GetDEKIfUnlocked(boxID string) ([]byte, error) {
if boxID != "" && !ast.IsNodeIDPattern(boxID) {
return nil, errors.New("invalid notebook ID")
}
if !IsEncryptedBox(boxID) {
return nil, nil
}
repairEncryptedBoxStateFromDEK(boxID)
if !isBoxUnlockedForAccess(boxID) {
return nil, errors.New("encrypted notebook is locked, please unlock it first")
}
cachedDEKsLock.RLock()
defer cachedDEKsLock.RUnlock()
dek, ok := cachedDEKs[boxID]
if !ok {
return nil, errors.New("encrypted notebook is locked, please unlock it first")
}
ret := make([]byte, len(dek))
copy(ret, dek)
return ret, nil
}
// HoldBoxReadLock 获取 box 读锁,防止 LockBox 在持锁期间清除缓存/临时文件。
// 调用方完成解密输出后必须调 ReleaseBoxReadLock。
func HoldBoxReadLock(boxID string) {
if !IsEncryptedBox(boxID) {
acquireBoxReadLock(boxID)
returnView on GitHub (pinned to 251596fc0d)
Solutions
- Prompt the user to unlock the encrypted notebook via UnlockBox (provide password), then retry the operation.
- If building automation, call UnlockBox(boxID, password) before any asset/doc operation and check its error before proceeding.
- Increase or disable the auto-lock timeout in notebook crypto settings if the lock fires too aggressively for the workflow.
Example fix
// before
dek, err := model.GetDEKIfUnlocked(boxID)
if err != nil { return err }
// after
dek, err := model.GetDEKIfUnlocked(boxID)
if err != nil {
if unlockErr := model.UnlockBox(boxID, password); unlockErr != nil {
return unlockErr
}
dek, err = model.GetDEKIfUnlocked(boxID)
if err != nil { return err }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check unlock state before calling GetDEKIfUnlocked
if model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {
// prompt user to unlock
} Try / catch
dek, err := model.GetDEKIfUnlocked(boxID)
if err != nil {
if strings.Contains(err.Error(), "locked") {
// prompt password, then:
if unlockErr := model.UnlockBox(boxID, password); unlockErr != nil {
return unlockErr
}
dek, err = model.GetDEKIfUnlocked(boxID)
}
if err != nil {
return err
}
} Prevention
- Wrap all encrypted-notebook asset operations in HoldBoxReadLock/ReleaseBoxReadLock.
- Keep the notebook unlocked for the duration of a multi-step export, then explicitly lock.
- Check isBoxUnlockedForAccess before scheduling long-running background jobs.
When it happens
Trigger: Any asset read/write, block-tree access, or file copy that calls GetDEKIfUnlocked after the auto-lock timer fires or after LockBox was called. Also occurs on a fresh kernel restart where the encrypted notebook has not yet been unlocked in this session.
Common situations: User left the app idle past the auto-lock interval and then tried to open an asset or export a doc. App was restarted and the encrypted notebook hasn't been unlocked yet. LockBox was triggered programmatically (e.g., by a sync or publish flow) while a long-running export was queued.
Related errors
- Please unlock the encrypted notebook first
- encrypted notebook is locked, please unlock it first
- encrypted .sy [%s]: base id [%s] != root id [%s]
- encrypted notebook key material is missing
- Encrypted notebooks already exist but the master key backup
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/4814b0d58c143996.
Report an issue: GitHub.