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

  1. Unlock the encrypted notebook (enter passphrase in UI or call the unlock API) and retry
  2. Guard callers with IsBoxUnlocked(ExtractBoxIDFromAssetsPath(absPath)) before invoking these asset APIs
  3. Adjust auto-lock timeout in the encrypted notebook settings if it locks too aggressively for the workflow
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/b86d85388c33c2a6. Report an issue: GitHub.