siyuan-note/siyuan · error

314

314

Error message

Please unlock the encrypted notebook first

What it means

Returned by readCurrentDocVersionData (history_diff.go:326) as Conf.Language(314) = "Please unlock the encrypted notebook first". Fires after the .sy file was read from disk and IsEncryptedBox(boxID) is true, but GetDEKIfUnlocked returned an error. The DEK (document encryption key) is only held in memory while the notebook is unlocked by the user; without it the ciphertext cannot be decrypted for diffing.

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 251596fc0d)

Solutions

  1. Prompt the user to unlock the encrypted notebook (Settings or the notebook context menu) and retry the diff.
  2. At the API layer, call holdEncryptedBoxRequest(c, boxID) before DiffDocVersions and return code 314 early so the frontend can route to the unlock UI.
  3. On the client, when a 314 is returned, open the unlock dialog and re-issue the original request on success.
Defensive patterns

Strategy: validation

Validate before calling

// Before DiffDocVersions, ensure encrypted notebooks are unlocked.
boxID, err := ResolveDocVersionBoxID(ref)
if err != nil { return err }
if boxID != "" && IsEncryptedBox(boxID) {
    if _, e := GetDEKIfUnlocked(boxID); e != nil {
        return errors.New(Conf.Language(314)) // prompt unlock
    }
}

Try / catch

diff, err := DiffDocVersions(left, right)
if err != nil && err.Error() == Conf.Language(314) {
    // open the notebook-unlock dialog, then retry
}

Prevention

When it happens

Trigger: DiffDocVersions or ResolveDocVersionBoxID against a current doc in an encrypted notebook whose lock has been released (session timeout, app restart, or explicit re-lock). The HTTP layer at api/history.go:231 also surfaces code 314 when holdEncryptedBoxRequest fails, so this is the model-layer duplicate.

Common situations: User restarted the app and the encrypted notebook auto-locked; a long-running diff dialog that outlasted the unlock session; multiple devices where the notebook is locked on this one.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/1629863fa88dc5b6. Report an issue: GitHub.