siyuan-note/siyuan · error
asset path contains an unresolved symbolic link [%s]
Error message
asset path contains an unresolved symbolic link [%s]
What it means
ResolveAssetPathWithMissingLeaf walks an asset path from the leaf upward to find the deepest existing prefix. When os.Stat fails with an error that is NOT 'not exist', but Lstat reveals the component is a symlink whose target cannot be resolved (dangling or looping symlink), it refuses to silently treat the path as missing-leaf material and returns 'asset path contains an unresolved symbolic link'. This guards the deferred asset-download mechanism against broken symlinks inside the data directory.
Source
Thrown at kernel/model/asset_download_read.go:46
)
// ResolveAssetPathWithMissingLeaf 校验尚未下载的路径,已存在的父目录仍须通过符号链接校验。
func ResolveAssetPathWithMissingLeaf(absPath string) (string, error) {
current := filepath.Clean(absPath)
var missing []string
for {
resolved, err := ResolveRealPath(current)
if err == nil {
for i := len(missing) - 1; i >= 0; i-- {
resolved = filepath.Join(resolved, missing[i])
}
return resolved, nil
}
if !os.IsNotExist(err) {
return "", err
}
if info, statErr := os.Lstat(current); statErr == nil && info.Mode()&os.ModeSymlink != 0 {
return "", fmt.Errorf("asset path contains an unresolved symbolic link [%s]", current)
}
parent := filepath.Dir(current)
if parent == current {
return "", err
}
missing = append(missing, filepath.Base(current))
current = parent
}
}
// deferredAssetPath 只解析同步清单,不访问网络,也不以未下载状态推断文件已删除。
func deferredAssetPath(relativePath, boxID string, includeEncrypted bool) (string, error) {
files, err := DeferredSyncAssets()
if err != nil {
return "", err
}
return deferredAssetPathFromFiles(relativePath, boxID, includeEncrypted, files)
}View on GitHub (pinned to 8641553a1f)
Solutions
- Find the offending symlink with `find data -xtype l` and remove or repair it so it points to an existing target
- Replace the symlink with a real copy of the target file inside the assets directory
- Re-run the asset resolution/download so the deferred pipeline can fetch the missing file into a real path
- If the symlink target exists on another mount, mount it before using the workspace
Example fix
// shell // before: data/assets/foo.png -> /mnt/old/foo.png (target gone) // after cp /mnt/new/foo.png data/assets/foo.png # or rm data/assets/foo.png and re-insert the asset
Defensive patterns
Strategy: fallback
Validate before calling
info, err := os.Lstat(assetPath)
if err == nil && info.Mode()&os.ModeSymlink != 0 {
if _, err := os.Stat(assetPath); err != nil {
return fmt.Errorf("dangling symlink at %s, repair before use", assetPath)
}
} Try / catch
resolved, err := model.ResolveDataAssetPath(relPath)
if err != nil && strings.Contains(err.Error(), "unresolved symbolic link") {
repaired, repErr := repairOrRemoveSymlink(relPath) // replace with real file
if repErr != nil { return repErr }
resolved, err = model.ResolveDataAssetPath(relPath)
} Prevention
- Periodically scan data/ with `find -xtype l` for dangling symlinks
- Copy real files into assets/ instead of symlinking across mounts
- Avoid filesystem-level copy tools that turn files into broken links on Windows
- Re-verify asset resolution after restoring a workspace from an archive
When it happens
Trigger: Calling getFile, ResolveDataAssetPath, or deferredAssetPath where a component of the asset path (e.g. assets/link -> missing/target) is a symlink pointing to a nonexistent target; also reached via unusedAssetsContainPath during asset cleanup scans.
Common situations: User copied a workspace between filesystems and symlinks broke; a sync tool replaced assets with dangling symlinks; a user manually created a symlink in assets/ to a path that no longer exists; a plugin rewrote asset paths as links.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- asset path resolves outside notebook assets directory
- resolve assets directory [%s] failed: %w
- symlink [%s] resolves outside assets directory: [%s]
- encrypted document is a symbolic link [%s]
- exporting symbolic links is not supported
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/0137a38a822d1b02.
Report an issue: GitHub.