siyuan-note/siyuan · warning
remove empty plugin storage directory [%s]: %w
Error message
remove empty plugin storage directory [%s]: %w
What it means
cleanupEmptyPluginStorageDirs walks <workspace>/data/storage/petals, and for directories containing neither files nor subdirectories calls removeEmptyDirectoryTree. Any removal failure (permissions, busy, symlink/IO errors) is collected as 'remove empty plugin storage directory [%s]: %w' and returned joined via errors.Join. Cleanup continues past failures, so the error reports one or more aggregated failures, not a fatal abort.
Source
Thrown at kernel/model/plugin_storage.go:95
if infoErr != nil {
cleanupErrors = append(cleanupErrors, fmt.Errorf("inspect plugin storage directory [%s]: %w", entry.Name(), infoErr))
continue
}
if !isDir || !bazaar.IsValidPackageName(entry.Name()) {
continue
}
dirPath := filepath.Join(storageRoot, entry.Name())
hasFile, readErr := containsFile(dirPath)
if readErr != nil {
cleanupErrors = append(cleanupErrors, fmt.Errorf("inspect plugin storage directory [%s]: %w", dirPath, readErr))
continue
}
if hasFile {
continue
}
if _, removeErr := removeEmptyDirectoryTree(dirPath); removeErr != nil {
cleanupErrors = append(cleanupErrors, fmt.Errorf("remove empty plugin storage directory [%s]: %w", dirPath, removeErr))
}
}
return errors.Join(cleanupErrors...)
}
func isRegularDirectoryEntry(entry os.DirEntry) (bool, error) {
if entry.Type()&os.ModeSymlink != 0 {
return false, nil
}
info, err := entry.Info()
if err != nil {
return false, err
}
return info.IsDir() && info.Mode()&os.ModeSymlink == 0, nil
}
func removeEmptyDirectoryTree(dirPath string) (removed bool, err error) {
entries, err := os.ReadDir(dirPath)View on GitHub (pinned to 8641553a1f)
Solutions
- Re-run cleanup after closing other SiYuan instances/plugins that may hold handles to the directory
- Fix permissions on data/storage/petals subdirectories so the kernel can delete them
- Inspect the wrapped %w error to identify the specific failing path and remove it manually
- Move cleanup to startup/shutdown windows when plugins are inactive
Example fix
// before: treat joined cleanup errors as fatal
if err := model.CleanupEmptyPluginStorageDirs(); err != nil { return err }
// after: log aggregated failures and continue
if errs := model.CleanupEmptyPluginStorageDirs(); errs != nil {
logging.LogWarnf("plugin storage cleanup incomplete: %s", errs)
} Defensive patterns
Strategy: try-catch
Validate before calling
const storageRoot = path.join(workspaceDir, "data", "storage", "petals");
try { fs.accessSync(storageRoot, fs.constants.W_OK); } catch (e) {
console.warn("plugin storage root not writable, cleanup may fail:", e.message);
} Try / catch
try {
await fetchPost("/api/petal/cleanupEmptyPluginStorageDirs", {});
} catch (e) {
logging.LogWarn("some empty plugin storage dirs could not be removed: " + e);
// non-fatal: retry later when no plugins are active
} Prevention
- Run cleanup at kernel startup/shutdown, not while plugins are active
- Keep data/storage/petals subdirectories writable by the kernel user
- Close other SiYuan instances sharing the workspace before cleanup
- Treat joined cleanup errors as warnings and inspect the wrapped per-path causes
When it happens
Trigger: Calling CleanupEmptyPluginStorageDirs when an empty plugin storage directory cannot be deleted — the directory was made read-only, a file appeared concurrently inside it, the OS reports it busy (open handle on Windows), or an unreadable/locked entry confuses the tree removal.
Common situations: Another running SiYuan instance or a plugin still writing into the directory during cleanup; Windows Explorer/AV holding a handle; permission drift after copying the workspace; removing dirs while the plugin is active.
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
- install local marketplace package failed: %w; rollback faile
- read session file failed: %w
- create session dir failed: %w
- save session file failed: %w
- read image failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/5a7f7ad3adab928d.
Report an issue: GitHub.