{"record":{"id":"9f2f16c3c706b792","repo":"siyuan-note/siyuan","slug":"remove-unused-asset-s-failed-w","errorCode":null,"errorMessage":"remove unused asset [%s] failed: %w","messagePattern":"remove unused asset \\[(.+?)\\] failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/assets.go","lineNumber":1473,"sourceCode":"\n\thistoryPath := filepath.Join(historyDir, filepath.FromSlash(relativePath))\n\tif err = filelock.Copy(absPath, historyPath); err != nil {\n\t\terr = fmt.Errorf(\"copy unused asset [%s] to history failed: %w\", absPath, err)\n\t\treturn\n\t}\n\n\thash, _ := util.GetEtag(absPath)\n\tsql.BatchRemoveAssetsQueue([]string{hash})\n\tcache.RemoveAssetHash(hash)\n\n\tif util.IsMobileContainer() {\n\t\tHandleAssetsRemoveEvent(absPath)\n\t}\n\n\tif err = filelock.RemoveWithoutFatal(absPath); err != nil {\n\t\tlogging.LogErrorf(\"remove unused asset [%s] failed: %s\", absPath, err)\n\t\tutil.PushErrMsg(fmt.Sprintf(\"%s\", err), 7000)\n\t\terr = fmt.Errorf(\"remove unused asset [%s] failed: %w\", absPath, err)\n\t\treturn\n\t}\n\tret = absPath\n\n\tutil.RemoveAssetText(relativePath)\n\n\tIncSync()\n\n\tindexHistoryDir(filepath.Base(historyDir), util.NewLute())\n\tcache.RemoveAsset(relativePath)\n\treturn\n}\n\nfunc RenameAsset(oldPath, newName string) (newPath string, err error) {\n\tutil.PushEndlessProgress(Conf.Language(110))\n\tdefer util.PushClearProgress()\n\n\toldCleanPath := AssetPathWithoutQuery(oldPath)","sourceCodeStart":1455,"sourceCodeEnd":1491,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/assets.go#L1455-L1491","documentation":"Returned by RemoveUnusedAsset (assets.go:1473) when filelock.RemoveWithoutFatal fails to delete the asset file after it was successfully copied to history. The asset has already been removed from the SQL index and cache (sql.BatchRemoveAssetsQueue, cache.RemoveAssetHash) and the remove event has been dispatched on mobile, so the file is the last on-disk artifact. The %w preserves the underlying remove error.","triggerScenarios":"Calling /api/asset/removeUnusedAsset when the asset file cannot be deleted: permission denied, file held open by another process, read-only mount, or the path is a directory unexpectedly. The preceding history copy succeeded, so the data is preserved but deletion is blocked.","commonSituations":"File open in an external viewer/editor (PDF reader, image editor); read-only assets directory; Windows file lock by antivirus/indexer; the asset was converted to a directory by a sync conflict.","solutions":["Inspect the wrapped err for EBUSY/EACCES/EPERM and close whatever process holds the file, then retry RemoveUnusedAsset.","Verify the assets directory is writable and not on a read-only mount.","Note the asset was already de-indexed and copied to history; if you retry and the source is now gone the function will still attempt removal and may report ENOENT — treat a vanished file as success rather than re-erroring."],"exampleFix":"// before: any remove error aborts after index/cache already updated\nif err = filelock.RemoveWithoutFatal(absPath); err != nil {\n    err = fmt.Errorf(\"remove unused asset [%s] failed: %w\", absPath, err)\n    return\n}\n\n// after: a vanished file is not fatal once history copy succeeded\nif err = filelock.RemoveWithoutFatal(absPath); err != nil {\n    if os.IsNotExist(err) {\n        err = nil\n    } else {\n        err = fmt.Errorf(\"remove unused asset [%s] failed: %w\", absPath, err)\n        return\n    }\n}","handlingStrategy":"try-catch","validationCode":"// Close any external handle before deletion; the kernel cannot force-remove a locked file.\nif (window.siyuan.mobile) await closeAssetViewers(absPath)","typeGuard":null,"tryCatchPattern":"// The asset is already de-indexed and history-copied; a vanished file is effectively success.\ntry {\n  await fetchPost('/api/asset/removeUnusedAsset', { path: p })\n} catch (e) {\n  if (/no such file|not exist/i.test(String(e.message))) return\n  throw e\n}","preventionTips":["Make sure no process holds the asset open (PDF reader, image editor, indexer).","Keep the assets directory writable and not on a read-only mount.","After a failure, re-run RemoveUnusedAsset — the prior history copy is preserved."],"tags":["assets","filesystem","cleanup","history","go"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}