siyuan-note/siyuan · error
remove unused asset [ ] failed
Error message
remove unused asset [%s] failed: %w
What it means
The kernel failed to delete an unused asset file from disk during asset cleanup. SiYuan removes assets that are no longer referenced by any document; when the underlying file removal (filelock.RemoveWithoutFatal) fails, the absolute path and OS error are wrapped and pushed to the UI as an error message. The original error is preserved via %w wrapping.
Solutions
- Check no other process (editor, sync client, antivirus) is holding the asset file open, then retry the removal
- Verify the data directory and workspace/assets folder are writable by the SiYuan process user
- Confirm the asset file still exists; if it was already removed by sync or another instance, refresh the asset panel
- Check disk health/free space and OS-level error details in the kernel log (logging.LogErrorf output)
- Restart SiYuan to release internal handles and retry the cleanup
Example fix
// before: removal fails silently blocking cleanup
if err = filelock.RemoveWithoutFatal(absPath); err != nil { ... }
// after (user-side): close the app holding the asset, ensure file is unlocked, then retry
closeExternalEditors(assetPath); retryAssetRemoval() Defensive patterns
Strategy: try-catch
Validate before calling
// before triggering cleanup, check writability
import fs from 'fs';
if (!fs.accessSync(assetAbsPath, fs.constants.W_OK)) throw new Error('asset not writable'); Try / catch
try { await removeUnusedAsset(path) } catch (e) {
if (e.message.includes('remove unused asset')) {
// file likely locked/permission issue; notify user to close editors/sync clients
showLockHint(path);
}
} Prevention
- Keep the workspace out of folders managed by aggressive sync/AV tools
- Close external editors holding asset files before bulk cleanup
- Run SiYuan with write permissions on the whole workspace
When it happens
Trigger: RemoveUnusedAsset / HandleAssetsRemoveEvent flow deletes an asset file and the OS remove fails — typically because the file is locked by another process (open in an external editor, AV scanner, sync client), the file was already deleted, or the user lacks write permission on the file or its parent directory.
Common situations: Cloud-sync clients (OneDrive/Dropbox) holding file locks on Windows; antivirus scanning the file mid-delete; read-only data directory; the asset deleted concurrently by another SiYuan instance or sync; filesystem errors on removable/network drives.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- accessing assets in encrypted notebook
- ambiguous asset path
- asset path must be a file
- Conf.Language(0)
- Conf.Language(0) (localized open notebook failure message)
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/9f2f16c3c706b792.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/assets.go:1631
historyPath := filepath.Join(historyDir, filepath.FromSlash(relativePath))
if err = filelock.Copy(absPath, historyPath); err != nil {
err = fmt.Errorf("copy unused asset [%s] to history failed: %w", absPath, err)
return
}
hash, _ := util.GetEtag(absPath)
sql.BatchRemoveAssetsQueue([]string{hash})
cache.RemoveAssetHash(hash)
if util.IsMobileContainer() {
HandleAssetsRemoveEvent(absPath)
}
if err = filelock.RemoveWithoutFatal(absPath); err != nil {
logging.LogErrorf("remove unused asset [%s] failed: %s", absPath, err)
util.PushErrMsg(fmt.Sprintf("%s", err), 7000)
err = fmt.Errorf("remove unused asset [%s] failed: %w", absPath, err)
return
}
ret = absPath
util.RemoveAssetText(relativePath)
IncSync()
indexHistoryDir(filepath.Base(historyDir), util.NewLute())
cache.RemoveAsset(relativePath)
return
}
func RenameAsset(oldPath, newName string) (newPath string, err error) {
util.PushEndlessProgress(Conf.Language(110))
defer util.PushClearProgress()
oldCleanPath := AssetPathWithoutQuery(oldPath)View on GitHub (pinned to 9f775e8a12)