{"record":{"id":"77507ef5c7f9aa0e","repo":"siyuan-note/siyuan","slug":"resolve-asset-s-failed-w","errorCode":null,"errorMessage":"resolve asset [%s] failed: %w","messagePattern":"resolve asset \\[(.+?)\\] failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/assets.go","lineNumber":1099,"sourceCode":"\tresolvedRoot, evalErr := ResolveAssetPathWithMissingLeaf(assetRoot)\n\tif evalErr != nil {\n\t\terr = fmt.Errorf(\"resolve assets directory [%s] failed: %w\", assetRoot, evalErr)\n\t\treturn\n\t}\n\tif assetDirIndex > 0 {\n\t\tnotebookRoot := filepath.Join(util.DataDir, parts[0])\n\t\tresolvedDataDir, dataEvalErr := ResolveRealPath(util.DataDir)\n\t\tresolvedNotebookRoot, notebookEvalErr := ResolveRealPath(notebookRoot)\n\t\tif dataEvalErr != nil || notebookEvalErr != nil ||\n\t\t\t!gulu.File.IsSubPath(resolvedDataDir, resolvedNotebookRoot) ||\n\t\t\t!gulu.File.IsSubPath(resolvedNotebookRoot, resolvedRoot) {\n\t\t\terr = fmt.Errorf(\"notebook asset path resolves outside notebook directory: %s\", assetPath)\n\t\t\treturn\n\t\t}\n\t}\n\tresolvedPath, evalErr := ResolveAssetPathWithMissingLeaf(absPath)\n\tif evalErr != nil {\n\t\terr = fmt.Errorf(\"resolve asset [%s] failed: %w\", absPath, evalErr)\n\t\treturn\n\t}\n\tif !gulu.File.IsSubPath(resolvedRoot, resolvedPath) {\n\t\terr = fmt.Errorf(\"asset path resolves outside assets directory: %s\", assetPath)\n\t\treturn\n\t}\n\n\trelativePath = filepath.ToSlash(dataRelativePath)\n\treturn\n}\n\n// ResolveUnusedDataAssetPath 解析 data 相对资源路径，并确认目标当前未被引用。\nfunc ResolveUnusedDataAssetPath(assetPath string) (relativePath, absPath string, err error) {\n\trelativePath, absPath, err = ResolveDataAssetPath(assetPath)\n\tif err != nil {\n\t\treturn\n\t}\n","sourceCodeStart":1081,"sourceCodeEnd":1117,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/assets.go#L1081-L1117","documentation":"ResolveDataAssetPath resolves a data-relative asset path and, as its final safety step, re-evaluates the full asset path through symlinks/junctions via ResolveAssetPathWithMissingLeaf. This error wraps any failure of that resolution (e.g. broken symlink, permission error, filesystem error) with the original absolute path for context. It is thrown to prevent proceeding with an unverifiable path.","triggerScenarios":"Calling ResolveDataAssetPath (directly or via ResolveUnusedDataAssetPath, PrepareAgentMessageImage, assetStat, deferredAssetPathFromFiles) with an absolute path whose trailing component cannot be resolved — most commonly a broken symlink pointing to a non-existent target, or a symlink loop/permission failure on any component.","commonSituations":"An asset file was deleted but a symlink to it remains in the workspace; a synced workspace restored symlinks whose targets are missing; moving a notebook outside the workspace while keeping symlinks inside assets/.","solutions":["Check the target of the wrapped path: run filepath.EvalSymlinks on it manually or `ls -l` / `readlink -f` to find the broken link","Delete or repair the dangling symlink inside <workspace>/data/.../assets/ so a real file exists at the target","If the asset genuinely should not exist, remove the stale reference from the document and re-run the operation","Ensure filesystem permissions allow the kernel process to traverse every directory component of the path"],"exampleFix":"// before: broken symlink left in assets\nln -s /nonexistent/target.png assets/foo.png\n// after: remove or repair the link\nrm assets/foo.png  # or: ln -s /valid/target.png assets/foo.png","handlingStrategy":"try-catch","validationCode":"if _, statErr := os.Stat(absPath); statErr != nil {\n\t// path or symlink target missing; repair before calling ResolveDataAssetPath\n}\nif real, evalErr := filepath.EvalSymlinks(absPath); evalErr != nil {\n\t// unresolvable symlink; remove or fix it first\n}","typeGuard":"func resolvableAsset(p string) bool {\n\t_, err := filepath.EvalSymlinks(p)\n\treturn err == nil\n}","tryCatchPattern":"rel, abs, err := model.ResolveDataAssetPath(assetPath)\nif err != nil {\n\tvar broken bool\n\tif _, evalErr := filepath.EvalSymlinks(abs); evalErr != nil {\n\t\tbroken = true // dangling symlink; clean up then retry\n\t}\n\treturn fmt.Errorf(\"asset %s unusable (broken=%v): %w\", assetPath, broken, err)\n}","preventionTips":["Never leave dangling symlinks inside <workspace>/data/**/assets/","After restoring a workspace from backup, audit symlink targets with `find data -type l -exec file {} \\;`","Check os.Stat/EvalSymlinks on asset paths before registering them in documents"],"tags":["filesystem","symlink","asset-resolution"],"backgroundTag":"file-not-found","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}