siyuan-note/siyuan · error

314

314

Error message

Conf.Language(314)

What it means

ensureReadableAssetLocal enforces that an asset belonging to an encrypted notebook can only be made locally readable when that notebook is unlocked; otherwise it returns i18n message 314 ('Please unlock the encrypted notebook first'). The check runs before downloading the raw ciphertext (EnsureAssetPrefixLocal); actual read still requires authenticated decryption afterwards.

Solutions

  1. Unlock the encrypted notebook (enter passphrase) and retry the operation
  2. In scripts/plugins, call the box unlock API and confirm IsBoxUnlocked(boxID) before these asset operations
  3. Reorder automation so unlocking happens first in the workflow
  4. Check ExtractBoxIDFromAssetsPath output to confirm the asset really belongs to the encrypted box you think it does

Example fix

// before
err := model.EnsureAssetLocal(absPath) // via ensureReadableAssetLocal
// after
boxID := model.ExtractBoxIDFromAssetsPath(absPath)
if model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {
    return promptUserToUnlock(boxID)
}
err := model.EnsureAssetLocal(absPath)
Defensive patterns

Strategy: try-catch

Validate before calling

boxID := model.ExtractBoxIDFromAssetsPath(absPath)
if boxID != "" && model.IsEncryptedBox(boxID) && !model.IsBoxUnlocked(boxID) {
    return errors.New(model.Conf.Language(314))
}

Try / catch

if err := model.EnsureAssetLocal(absPath); err != nil {
    if strings.Contains(err.Error(), model.Conf.Language(314)) {
        if uerr := unlockBox(boxID); uerr != nil { return uerr }
        return model.EnsureAssetLocal(absPath) // retry once after unlock
    }
    return err
}

Prevention

When it happens

Trigger: Called by readAssetBytesInBox, uploadAssets2Cloud, RenameAsset, and PrepareRichClipboardAssets when the target asset's box (ExtractBoxIDFromAssetsPath) is an encrypted box and IsBoxUnlocked returns false — e.g. after kernel restart or manual lock.

Common situations: Copying rich-text content containing encrypted-notebook assets to the clipboard; renaming or re-uploading assets in a locked encrypted notebook; background jobs operating on encrypted boxes without the user having unlocked them.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/a7be4cd01c91fe74. Report an issue: GitHub.

Appendix: 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 9f775e8a12)