siyuan-note/siyuan · error
asset is not unused
Error message
asset is not unused: %s
What it means
ResolveUnusedDataAssetPath wraps ResolveDataAssetPath and additionally checks that the target asset appears in the current list of unreferenced assets (UnusedAssets). This error is thrown when the asset exists and resolves fine, but is still referenced by at least one document, so deleting it would break content. It guards RemoveUnusedAsset against destroying in-use files.
Solutions
- Run assets/remove-unused-objects (the batch 'remove all unused assets' operation) after re-scanning, so only currently-unused items are removed
- Remove or update the document references to the asset first, wait for indexing to complete, then retry the delete
- Verify references with an SQL query over blocks for the asset path before deleting
- If you are sure the reference is stale, force a re-index of the notebook and retry
Example fix
// before: delete may hit a referenced asset
abs, err := model.ResolveUnusedDataAssetPath(p)
// after: guard and fall back to the scan-based bulk removal
if err != nil { log.Warnf("skip %s: %v", p, err); return }
abs, _ := model.ResolveUnusedDataAssetPath(p) Defensive patterns
Strategy: fallback
Validate before calling
refs, err := sql.Query("SELECT count(1) FROM blocks WHERE content LIKE '%assets/your-file.png%'")
// if refs > 0 the asset is in use; skip deletion Try / catch
rel, abs, err := model.ResolveUnusedDataAssetPath(p)
if err != nil {
if strings.Contains(err.Error(), "is not unused") {
// asset referenced; defer deletion or remove references first
return nil
}
return err
} Prevention
- Run the full 'remove unused assets' scan instead of deleting individual assets
- Re-index notebooks after editing documents so the unused-assets list is fresh
- Avoid concurrent document edits and asset deletions in automation scripts
When it happens
Trigger: Calling ResolveUnusedDataAssetPath (via RemoveUnusedAsset API) with a path whose asset is referenced by any document, or when the unused-assets scan is stale relative to a reference just added.
Common situations: A user or automation tries to delete an asset that a recently edited document links to; two concurrent operations where one inserts a reference between the scan and the delete; cache/index lag making the unused list outdated.
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
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/7c5ef8db631fd506.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/assets.go:1121
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
}
if unusedAssetsContainPath(relativePath, absPath, UnusedAssets(false)) {
return
}
err = fmt.Errorf("asset is not unused: %s", relativePath)
return
}
func unusedAssetsContainPath(relativePath, absPath string, items []*UnusedItem) bool {
resolvedPath, _ := ResolveAssetPathWithMissingLeaf(absPath)
for _, item := range items {
if item.AbsPath != "" {
resolvedItemPath, evalErr := ResolveAssetPathWithMissingLeaf(item.AbsPath)
samePath, relErr := filepath.Rel(resolvedPath, resolvedItemPath)
if resolvedPath != "" && evalErr == nil && relErr == nil && samePath == "." {
return true
}
continue
}
itemPath := filepath.ToSlash(filepath.Clean(filepath.FromSlash(item.Item)))
if itemPath == relativePath {
return true
}View on GitHub (pinned to 9f775e8a12)