siyuan-note/siyuan · error
resolve assets directory [%s] failed: %w
Error message
resolve assets directory [%s] failed: %w
What it means
Thrown by ResolveDataAssetPath (kernel/model/assets.go:951) when filepath.EvalSymlinks fails on the reconstructed assets root directory (either global `data/assets/` or a notebook's `<boxID>/assets/`). EvalSymlinks fails when the directory does not exist, when any link in the chain is broken, or when the process lacks permission to traverse a component.
Source
Thrown at kernel/model/assets.go:951
return
}
}
}
if assetDirIndex < 0 {
err = fmt.Errorf("path is not under an assets directory: %s", assetPath)
return
}
assetRootParts := parts[:assetDirIndex+1]
assetRoot := filepath.Join(util.DataDir, filepath.FromSlash(strings.Join(assetRootParts, "/")))
if !gulu.File.IsSubPath(assetRoot, absPath) {
err = fmt.Errorf("path is not a child of assets directory: %s", assetPath)
return
}
resolvedRoot, evalErr := filepath.EvalSymlinks(assetRoot)
if evalErr != nil {
err = fmt.Errorf("resolve assets directory [%s] failed: %w", assetRoot, evalErr)
return
}
if assetDirIndex > 0 {
notebookRoot := filepath.Join(util.DataDir, parts[0])
resolvedDataDir, dataEvalErr := filepath.EvalSymlinks(util.DataDir)
resolvedNotebookRoot, notebookEvalErr := filepath.EvalSymlinks(notebookRoot)
if dataEvalErr != nil || notebookEvalErr != nil ||
!gulu.File.IsSubPath(resolvedDataDir, resolvedNotebookRoot) ||
!gulu.File.IsSubPath(resolvedNotebookRoot, resolvedRoot) {
err = fmt.Errorf("notebook asset path resolves outside notebook directory: %s", assetPath)
return
}
}
resolvedPath, evalErr := filepath.EvalSymlinks(absPath)
if evalErr != nil {
err = fmt.Errorf("resolve asset [%s] failed: %w", absPath, evalErr)
return
}View on GitHub (pinned to 251596fc0d)
Solutions
- Check whether the assets root printed in [%s] actually exists on disk: `ls -la` on that path and each parent.
- If it is a broken symlink, remove it and let SiYuan recreate the directory (or restore from backup).
- Fix ownership/permissions so the kernel process can traverse every component (chmod +x on parent dirs, chown to the running user).
- If the assets directory legitimately should not exist for this notebook, do not call ResolveDataAssetPath for it; gate the call on existence first.
Defensive patterns
Strategy: validation
Validate before calling
// Ensure the assets root exists and is resolvable before resolving.
assetRoot := filepath.Join(util.DataDir, "assets") // or <box>/assets
if _, err := filepath.EvalSymlinks(assetRoot); err != nil {
return fmt.Errorf("assets root unavailable, refusing to resolve: %w", err)
} Try / catch
if _, _, err := model.ResolveDataAssetPath(p); err != nil {
if strings.Contains(err.Error(), "resolve assets directory") {
// surface a user-facing 'assets folder missing' message rather than a raw stack
}
return err
} Prevention
- Keep the workspace on a local, non-removable filesystem to avoid missing assets roots.
- After moving the workspace, run a consistency check so broken symlinks/missing dirs are recreated.
- Run the kernel under a user that owns or can traverse the entire DataDir path.
When it happens
Trigger: Calling ResolveDataAssetPath with a path whose `assets` directory component does not exist on disk (e.g. the notebook's assets folder was deleted or never created), or where the assets directory is a dangling symlink, or where a parent directory has restrictive permissions (0o000 / owned by another user).
Common situations: Workspace was copied/moved between machines and symlinks broke; a notebook directory was partially deleted leaving a conf.json but no assets/ dir; running the kernel under a different OS user than the one that owns DataDir; backup restore that recreated files but not directory symlinks.
Related errors
- resolve assets root [%s] failed: %w
- resolve asset [%s] failed: %w
- asset path resolves outside assets directory: %s
- [%s] is not sub path of workspace
- symlink [%s] resolves outside workspace: [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/12b3de77773b2c67.
Report an issue: GitHub.