siyuan-note/siyuan · error
Please unlock the encrypted notebook first
Error message
Please unlock the encrypted notebook first
What it means
Returned by copyAssetDecryptIfEncrypted when GetDEKIfUnlocked fails for the source box — the encrypted notebook is locked. The function is fail-closed: it refuses to copy rather than copying ciphertext (which would produce an unusable file at the destination). The message comes from Conf.Language(314): 'Please unlock the encrypted notebook first'.
Source
Thrown at kernel/model/crypto.go:2513
return &crypt, nil
}
// copyAssetDecryptIfEncrypted 把 srcPath 的 asset 复制到 destPath。
// 若 srcPath 在已解锁的加密笔记本下,读密文→解密→写明文到 destPath(导出目录);
// 否则走 filelock.Copy 原路径(字节级复制,密文/明文均可)。
func copyAssetDecryptIfEncrypted(srcPath, destPath string) error {
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
return err
}
boxID := ExtractBoxIDFromAssetsPath(srcPath)
if boxID != "" && IsEncryptedBox(boxID) {
HoldBoxReadLock(boxID)
defer ReleaseBoxReadLock(boxID)
dek, err := GetDEKIfUnlocked(boxID)
if err != nil {
// 加密笔记本未解锁:fail-closed,拒绝复制(不复制密文,避免泄漏无效文件)
return errors.New(Conf.Language(314))
}
raw, readErr := filelock.ReadFile(srcPath)
if readErr != nil {
return readErr
}
diskName := filepath.Base(srcPath)
plain, decErr := DecryptAsset(boxID, diskName, dek, raw)
if decErr != nil {
return errors.New(Conf.Language(316))
}
if err := filelock.WriteFile(destPath, plain); err != nil {
return err
}
return nil
}
return filelock.Copy(srcPath, destPath)
}
View on GitHub (pinned to 251596fc0d)
Solutions
- Unlock the encrypted notebook (UnlockBox with the user's password) and retry the copy/export.
- Surface a clear UI prompt telling the user which notebook needs unlocking, rather than a generic copy failure.
- For background jobs, check isBoxUnlockedForAccess(boxID) before scheduling asset operations and defer or queue the job if locked.
Defensive patterns
Strategy: try-catch
Validate before calling
// Check unlock state before triggering asset copy
if model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {
return fmt.Errorf("please unlock notebook %s first", boxID)
} Try / catch
err := copyAssetDecryptIfEncrypted(src, dst)
if err != nil {
msg := err.Error()
if strings.Contains(msg, "unlock") {
// surface unlock prompt to user, retry after unlock
}
return err
} Prevention
- Check isBoxUnlockedForAccess before scheduling asset copy/export jobs.
- For background/publish flows, defer asset operations until the notebook is confirmed unlocked.
- Show a clear UI message naming the locked notebook rather than a generic copy failure.
When it happens
Trigger: An asset copy/export operation (e.g., export to temp, publish, or asset serving) hits copyAssetDecryptIfEncrypted while the source notebook's DEK is not in memory. Triggered during export, thumbnail generation, or asset serving for a locked encrypted notebook.
Common situations: User attempts to export or preview an asset from an encrypted notebook that auto-locked. Publish/sync background job runs after the auto-lock timer fired. Fresh app start where the notebook wasn't unlocked.
Related errors
- encrypted notebook is locked, please unlock it first
- encrypted asset metadata is too large
- invalid encrypted asset format
- invalid encrypted asset metadata size
- Please unlock the encrypted notebook first
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/45a63e525e292715.
Report an issue: GitHub.