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

  1. Unlock the encrypted notebook by supplying the correct passphrase through the unlock dialog / unlock API so GetDEKIfUnlocked succeeds, then retry the operation.
  2. 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.
  3. If calling programmatically, check unlock state first and prompt the user to unlock before invoking history/diff endpoints.
  4. 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

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


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)