siyuan-note/siyuan · error
Conf.Language(314)
Error message
Conf.Language(314)
What it means
ensureReadableAssetLocal enforces that, before any raw ciphertext of an asset is downloaded/made locally readable, the asset's owning notebook, if encrypted, must be unlocked; otherwise it returns the localized Conf.Language(314) message. This ordering guarantee (access check first, download second) means the actual read afterwards still requires authenticated decryption.
Source
Thrown at kernel/model/asset_download_read.go:131
}
}
if lookupPath == relativePath {
return absPath, nil
}
candidates = append(candidates, absPath)
}
sort.Strings(candidates)
if len(candidates) > 0 {
return candidates[0], nil
}
return "", nil
}
// ensureReadableAssetLocal 先检查加密笔记本准入,再下载原始密文;实际读取仍须认证解密。
func ensureReadableAssetLocal(absPath string) error {
boxID := ExtractBoxIDFromAssetsPath(absPath)
if boxID != "" && IsEncryptedBox(boxID) && !IsBoxUnlocked(boxID) {
return errors.New(Conf.Language(314))
}
if gulu.File.IsSubPath(util.DataDir, absPath) {
if err := EnsureAssetPrefixLocal(absPath); err != nil {
return err
}
}
return EnsureAssetLocal(absPath)
}
// prepareExportAssets 在导出持有笔记本读锁或生成产物之前补齐文档引用的资源。
func prepareExportAssets(boxID string, docPaths []string, includeFootnotes ...bool) error {
if boxID != "" && IsEncryptedBox(boxID) && !IsBoxUnlocked(boxID) {
return errors.New(Conf.Language(314))
}
deferred, err := DeferredSyncAssets()
if err != nil || len(deferred) == 0 {
return err
}View on GitHub (pinned to 8641553a1f)
Solutions
- Unlock the encrypted notebook (enter passphrase in UI or call the unlock API) and retry
- Guard callers with IsBoxUnlocked(ExtractBoxIDFromAssetsPath(absPath)) before invoking these asset APIs
- Adjust auto-lock timeout in the encrypted notebook settings if it locks too aggressively for the workflow
- Re-enter the passphrase if the unlock attempt itself failed due to a wrong password
Example fix
// before
err := model.RenameAsset(oldPath, newPath) // notebook locked
// after
if box := model.ExtractBoxIDFromAssetsPath(oldPath); model.IsEncryptedBox(box) && !model.IsBoxUnlocked(box) {
return fmt.Errorf("unlock notebook %s first", box)
}
err := model.RenameAsset(oldPath, newPath) Defensive patterns
Strategy: validation
Validate before calling
boxID := model.ExtractBoxIDFromAssetsPath(absPath)
if boxID != "" && model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {
return errors.New("unlock notebook " + boxID + " first")
} Try / catch
if err := model.RenameAsset(old, new); err != nil && strings.Contains(err.Error(), conf.Conf.Language(314)) {
promptUserToUnlock(boxID) // then retry
return err
} Prevention
- Check lock state before batch asset operations (rename/upload/clipboard)
- Handle auto-lock: re-check IsBoxUnlocked between long batch steps
- Unlock all encrypted boxes at the start of automation jobs
- Show the localized 314 message to end users rather than raw errors
When it happens
Trigger: readAssetBytesInBox, uploadAssets2Cloud, RenameAsset, or PrepareRichClipboardAssets invoked with absPath inside an encrypted box that is currently locked (fresh start, auto-lock, or lock explicitly engaged).
Common situations: Plugin performs clipboard asset preparation or asset rename while the encrypted notebook has auto-locked; a batch asset-upload job runs overnight after the box locked; scripting against the kernel API without unlocking first.
Related errors
- source is not an encrypted asset
- %s
- Conf.Language(314)
- accessing assets in encrypted notebook [%s] is not supported
- encrypted notebook is not accessible
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/b86d85388c33c2a6.
Report an issue: GitHub.