{"record":{"id":"7c5ef8db631fd506","repo":"siyuan-note/siyuan","slug":"asset-is-not-unused-s","errorCode":null,"errorMessage":"asset is not unused: %s","messagePattern":"asset is not unused: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"kernel/model/assets.go","lineNumber":989,"sourceCode":"\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\n\tif unusedAssetsContainPath(relativePath, absPath, UnusedAssets(false)) {\n\t\treturn\n\t}\n\terr = fmt.Errorf(\"asset is not unused: %s\", relativePath)\n\treturn\n}\n\nfunc unusedAssetsContainPath(relativePath, absPath string, items []*UnusedItem) bool {\n\tresolvedPath, _ := filepath.EvalSymlinks(absPath)\n\tfor _, item := range items {\n\t\tif item.AbsPath != \"\" {\n\t\t\tresolvedItemPath, evalErr := filepath.EvalSymlinks(item.AbsPath)\n\t\t\tsamePath, relErr := filepath.Rel(resolvedPath, resolvedItemPath)\n\t\t\tif resolvedPath != \"\" && evalErr == nil && relErr == nil && samePath == \".\" {\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\titemPath := filepath.ToSlash(filepath.Clean(filepath.FromSlash(item.Item)))\n\t\tif itemPath == relativePath {\n\t\t\treturn true\n\t\t}","sourceCodeStart":971,"sourceCodeEnd":1007,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/assets.go#L971-L1007","documentation":"Thrown by ResolveUnusedDataAssetPath (kernel/model/assets.go:989) after the path resolved successfully but the asset is NOT present in the computed unused-asset list (UnusedAssets(false)). It is a business-rule guard, not a security or filesystem error: the caller asked to operate on an unused asset, but the asset is still referenced by some block, so the operation is refused.","triggerScenarios":"Calling ResolveUnusedDataAssetPath (used by cli/cmd/asset.go:120 for `siyuan asset` cleanup and by model.RemoveUnusedAsset / assets.go:1446) with an asset path whose file is still referenced in at least one document. The unused-asset scan re-checks references, and because the asset is referenced, it is absent from the unused list.","commonSituations":"Running a cleanup/delete on an asset the user believes is unused but is still embedded in a note; a reference that was thought to be deleted but remains in the blocktree (stale SQL rows not yet flushed); calling cleanup right after re-linking the asset elsewhere.","solutions":["Confirm the asset is genuinely unused: search the notebook for the filename and remove/replace every reference.","Force the unused-asset index to refresh (re-index the relevant notebooks) so references are accurately counted, then retry.","If you must remove a still-referenced asset, use the explicit delete API (which will also rewrite references) rather than the unused-asset path.","Do not catch-and-ignore; removing a referenced asset would create broken links."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Confirm the asset is in the unused set before attempting an unused-asset operation.\nunused := model.UnusedAssets(false)\nfound := false\nfor _, it := range unused {\n    if it.Item == p || it.AbsPath == abs { found = true; break }\n}\nif !found { return fmt.Errorf(\"asset %s is still referenced; use the referenced-asset delete path\", p) }","typeGuard":null,"tryCatchPattern":"if _, _, err := model.ResolveUnusedDataAssetPath(p); err != nil {\n    if strings.Contains(err.Error(), \"not unused\") {\n        // still referenced — re-index, then retry, or use the explicit delete API that rewrites references\n    }\n}","preventionTips":["Re-index notebooks before cleanup so the unused-asset list is accurate.","Prefer the explicit delete API when you know references exist, so links are rewritten.","Do not catch-and-delete anyway; that creates broken asset references."],"tags":["assets","unused-assets","validation","business-rule"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}