siyuan-note/siyuan · error
Conf.Language(12)
Error message
Conf.Language(12)
What it means
GetAssetAbsPathInBox fails to resolve an asset file path inside a specific notebook (box). The localized message Conf.Language(12) formats as "Query asset failed [%s]" with the relative asset path. It is thrown when deferred resolution failed and the box is encrypted, so direct filesystem lookup is intentionally skipped because encrypted-notebook assets are isolated and must not leak outside the encryption boundary.
Solutions
- Check IsEncryptedBox(boxID) before calling and route through the encrypted-asset read path (e.g. deferredAssetPath / serveEncryptedAsset) instead of direct path resolution
- Verify the asset actually exists in the encrypted box's storage; if it was moved or renamed, update the doc's asset links
- If the box was encrypted after the asset was added, re-index the notebook so the deferred asset mapping is up to date
- Handle the error as 'asset unavailable in encrypted box' and surface a user-facing message rather than retrying the same lookup
Example fix
// before
path, err := model.GetAssetAbsPathInBox(relPath, boxID)
if err != nil { log.Fatal(err) }
// after
if model.IsEncryptedBox(boxID) {
path, err = model.DeferredAssetPath(relPath, boxID) // encrypted-aware resolution
} else {
path, err = model.GetAssetAbsPath(relPath)
}
if err != nil { return fmt.Errorf("asset %s unavailable: %w", relPath, err) } Defensive patterns
Strategy: validation
Validate before calling
if model.IsEncryptedBox(boxID) {
// use encrypted-aware resolution instead of GetAssetAbsPathInBox
} Try / catch
path, err := model.GetAssetAbsPathInBox(rel, boxID)
if err != nil {
return fmt.Errorf("asset %s unavailable in box %s: %w", rel, boxID, err)
} Prevention
- Check IsEncryptedBox before direct asset path resolution
- Use deferredAssetPath/encrypted-aware APIs for encrypted notebooks
- Keep encrypted notebook indexes up to date after edits
When it happens
Trigger: Calling GetAssetAbsPathInBox(relativePath, boxID) where deferredAssetPath returns nothing (or errors that are treated as not-found) and IsEncryptedBox(boxID) is true, so the function returns fmt.Errorf(Conf.Language(12), relativePath) instead of searching the encrypted box's files directly.
Common situations: Resolving an image or file annotation path for a doc in an encrypted notebook while the asset record still points at the encrypted box; exporters (prepareExportAssets) or size probes (GetAssetImgSizeInBox) hitting encrypted-box assets whose on-disk names differ from the logical asset path.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- 314
- accessing assets in encrypted notebook
- assetPath is not an image referenced by the document
- Conf.Language(0)
- Conf.Sync.Stat
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/3037bb5cc2857080.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/assets.go:1265
// 验证解析后的路径仍在 <boxID>/assets/ 或全局 data/assets/ 下
expectedPrefix := filepath.Join(util.DataDir, "assets")
if boxID != "" {
expectedPrefix = filepath.Join(util.DataDir, boxID, "assets")
}
if !gulu.File.IsSubPath(expectedPrefix, realP) {
return "", fmt.Errorf("symlink [%s] resolves outside assets directory: [%s]", p, realP)
}
}
return p, nil
}
// 非加密 box 的资源可能回退到全局 data/assets(兼容旧笔记本结构)
if deferredPath, deferredErr := deferredAssetPath(relativePath, boxID, true); deferredErr != nil || deferredPath != "" {
return deferredPath, deferredErr
}
if !IsEncryptedBox(boxID) {
return GetAssetAbsPathWithOpt(relativePath, false)
}
return "", fmt.Errorf(Conf.Language(12), relativePath)
}
// GetAssetAbsPathWithOpt 与 GetAssetAbsPath 一致,但可通过 includeEncrypted 控制是否遍历加密 box。
// serveAssets 传 true(下游 serveEncryptedAsset 会按锁定状态 fail-closed),其他调用方传 false(安全跳过)。
func GetAssetAbsPathWithOpt(relativePath string, includeEncrypted bool) (string, error) {
relativePath = strings.TrimSpace(relativePath)
if idx := strings.Index(relativePath, "?"); idx >= 0 {
relativePath = relativePath[:idx]
}
absPath, err := getAssetAbsPath(relativePath, includeEncrypted)
if err == nil && absPath != "" {
return absPath, nil
}
if err != nil {
return "", err
}View on GitHub (pinned to 9f775e8a12)