siyuan-note/siyuan · error
Conf.Language(314)
Error message
Conf.Language(314)
What it means
When loading the current version of a document belonging to an encrypted notebook, the kernel reads the encrypted .sy file and then calls GetDEKIfUnlocked to obtain the notebook's data-encryption key. If the notebook is encrypted but its key is not currently unlocked (no passphrase supplied / vault locked), it surfaces the localized message keyed 314 (the notebook encryption unlock prompt) instead of proceeding to DecryptFile. This is a deliberate guard so ciphertext is never read without authentication.
Solutions
- Unlock the encrypted notebook by supplying the correct passphrase through the unlock dialog / unlock API so GetDEKIfUnlocked succeeds, then retry the operation.
- Verify the notebook actually has encryption enabled (IsEncryptedBox) and that the key envelope is intact; if the key is lost, restore from backup rather than bypassing.
- If calling programmatically, check unlock state first and prompt the user to unlock before invoking history/diff endpoints.
- Restart flow: re-enter the passphrase after kernel restart; keys are never persisted unlocked.
Example fix
// before: diff API called while notebook locked
POST /api/history/convertHistoryDiff doc in encrypted notebook -> Conf.Language(314)
// after: unlock first
POST /api/repo/unlockNotebook { "box": "20240101120000-abc", "password": "..." }
// then retry the history diff request Defensive patterns
Strategy: validation
Validate before calling
// Go: check unlock state before requesting the current doc version
if model.IsEncryptedBox(boxID) {
if _, err := model.GetDEKIfUnlocked(boxID); err != nil {
return fmt.Errorf("notebook %s is locked; unlock it before diffing", boxID)
}
} Try / catch
catch (e) { if (e.msg.includes(Langs[314])) { showNotebookUnlockDialog(box); } else { throw e; } } Prevention
- Unlock all encrypted notebooks at session start before invoking history/diff APIs
- Check IsEncryptedBox + unlock state before any version operation
- Treat kernel restarts as clearing unlocked keys; re-run the unlock flow
When it happens
Trigger: Calling any history-diff / doc-version API that resolves the CURRENT document for a notebook with encryption enabled while the notebook's DEK is not unlocked, e.g. GetDEKIfUnlocked(boxID) returns an error because the passphrase was never provided this session or the vault was relocked.
Common situations: User enabled notebook encryption but the unlock prompt was dismissed or the key cache expired; a kernel restart cleared unlocked keys; an API caller (plugin/script) hits the diff endpoint before the user unlocked the encrypted notebook; wrong passphrase entered earlier left the notebook locked.
Related errors
- Conf.Language(314)
- CLI does not support encrypted notebook history
- Conf.Language(314)
- Conf.Language(314)
- Conf.Language(314)
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/12cecd497b63dbf9.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/history_diff.go:326
func readCurrentDocVersionData(blockTree *treenode.BlockTree) (ret []byte, err error) {
relPath, err := filesys.ValidateBoxRelativePath(blockTree.BoxID, blockTree.Path)
if err != nil {
return nil, err
}
encrypted := IsEncryptedBox(blockTree.BoxID)
if encrypted {
HoldBoxReadLock(blockTree.BoxID)
defer ReleaseBoxReadLock(blockTree.BoxID)
}
absPath := filepath.Join(util.DataDir, blockTree.BoxID, filepath.FromSlash(relPath))
ret, err = filelock.ReadFile(absPath)
if err != nil || !encrypted {
return
}
dek, err := GetDEKIfUnlocked(blockTree.BoxID)
if err != nil {
return nil, errors.New(Conf.Language(314))
}
ret, err = DecryptFile(blockTree.BoxID, relPath, dek, ret)
return
}
func loadHistoryDocVersion(historyPath string) (ret *loadedDocVersion, err error) {
absPath, err := validateHistoryPath(historyPath)
if err != nil {
return nil, err
}
if !strings.HasSuffix(strings.ToLower(absPath), ".sy") {
return nil, errors.New("history version is not a document")
}
relPath, err := filepath.Rel(util.HistoryDir, absPath)
if err != nil {
return nil, err
}
parts := strings.SplitN(filepath.ToSlash(relPath), "/", 3)View on GitHub (pinned to 9f775e8a12)