siyuan-note/siyuan · error

resolve asset [ ] failed

Error message

resolve asset [%s] failed: %w

What it means

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.

Solutions

  1. Check the target of the wrapped path: run filepath.EvalSymlinks on it manually or `ls -l` / `readlink -f` to find the broken link
  2. Delete or repair the dangling symlink inside <workspace>/data/.../assets/ so a real file exists at the target
  3. If the asset genuinely should not exist, remove the stale reference from the document and re-run the operation
  4. Ensure filesystem permissions allow the kernel process to traverse every directory component of the path

Example fix

// before: broken symlink left in assets
ln -s /nonexistent/target.png assets/foo.png
// after: remove or repair the link
rm assets/foo.png  # or: ln -s /valid/target.png assets/foo.png
Defensive patterns

Strategy: try-catch

Validate before calling

if _, statErr := os.Stat(absPath); statErr != nil {
	// path or symlink target missing; repair before calling ResolveDataAssetPath
}
if real, evalErr := filepath.EvalSymlinks(absPath); evalErr != nil {
	// unresolvable symlink; remove or fix it first
}

Type guard

func resolvableAsset(p string) bool {
	_, err := filepath.EvalSymlinks(p)
	return err == nil
}

Try / catch

rel, abs, err := model.ResolveDataAssetPath(assetPath)
if err != nil {
	var broken bool
	if _, evalErr := filepath.EvalSymlinks(abs); evalErr != nil {
		broken = true // dangling symlink; clean up then retry
	}
	return fmt.Errorf("asset %s unusable (broken=%v): %w", assetPath, broken, err)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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/.

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


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/77507ef5c7f9aa0e. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/assets.go:1099

	resolvedRoot, evalErr := ResolveAssetPathWithMissingLeaf(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 := ResolveRealPath(util.DataDir)
		resolvedNotebookRoot, notebookEvalErr := ResolveRealPath(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 := ResolveAssetPathWithMissingLeaf(absPath)
	if evalErr != nil {
		err = fmt.Errorf("resolve asset [%s] failed: %w", absPath, evalErr)
		return
	}
	if !gulu.File.IsSubPath(resolvedRoot, resolvedPath) {
		err = fmt.Errorf("asset path resolves outside assets directory: %s", assetPath)
		return
	}

	relativePath = filepath.ToSlash(dataRelativePath)
	return
}

// ResolveUnusedDataAssetPath 解析 data 相对资源路径,并确认目标当前未被引用。
func ResolveUnusedDataAssetPath(assetPath string) (relativePath, absPath string, err error) {
	relativePath, absPath, err = ResolveDataAssetPath(assetPath)
	if err != nil {
		return
	}

View on GitHub (pinned to 9f775e8a12)