siyuan-note/siyuan · error
Conf.Language(387)
Error message
Conf.Language(387)
What it means
removeBoxDir retries deleting the notebook directory (e.g. during unmount or sync-cleanup); if the final attempt still fails, it returns the localized message for language key 387, formatted with the path and either the residual-entry description (files that could not be removed) or the last error text. It signals that the notebook directory could not be fully removed from disk.
Solutions
- Close any program holding files in the notebook folder (editors, file previews, antivirus scans), then retry unmount/remove
- Check that data/<notebook>/ and its contents are writable (on Windows remove read-only flags; on Unix check permissions/ownership)
- Pause third-party sync/backup tools watching the workspace, delete the residual files listed in the error manually, and retry
Defensive patterns
Strategy: try-catch
Validate before calling
async function canWriteDir(dir) {
try { const probe = dir + "/.probe"; await writeTextFile(probe, "x"); await removeFile(probe); return true; }
catch { return false; }
} Try / catch
try { await removeNotebook(boxID); } catch (e) { if (isLangMsg(e, 387)) { showTip("Close apps locking the notebook folder, delete residual files, then retry"); } } Prevention
- Close file previews, editors, and cloud-sync clients that open files under data/ before unmounting
- Exclude the SiYuan workspace from aggressive antivirus real-time scans
- After a failed sync, clear residual entries before retrying notebook removal
When it happens
Trigger: Unmounting/removing a notebook (RemoveBox, mountBox, or cleanupSyncedBoxResiduals) while files under data/<boxID>/ are locked or unwritable — an editor/index process holding handles, read-only filesystem, or sync leaving residual entries that cannot be deleted.
Common situations: On Windows: files opened by another program (preview tools, antivirus, cloud-sync clients) locking .sy assets; permission problems after restoring from backup; leftover residual entries after a partially failed sync.
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
- can not open file, just support open folder only
- can not remove [ ] caused by it is not a dir
- Create notebook [ ] folder [ ] failed
- Move notebook [ ] file [ ] failed
- Query notebook failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/8cd607e01043a46b.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/mount.go:230
}
return nil
}); nil != walkErr {
logging.LogWarnf("list residual entries of [%s] failed: %s", p, walkErr)
}
hasResidual := 0 < len(residual)
lastAttempt := 4 == i
// 先清空残留内容(深路径优先),下一轮重试再删除目录本身,避免 RemoveAll 再次卡在"目录非空"
sort.Sort(sort.Reverse(sort.StringSlice(residual)))
for _, rel := range residual {
if removeErr := filelock.RemoveWithoutFatal(filepath.Join(p, rel)); nil != removeErr {
logging.LogWarnf("remove residual entry [%s] failed: %s", rel, removeErr)
}
}
if lastAttempt {
if hasResidual {
err = fmt.Errorf(Conf.Language(387), p, strings.Join(describeResidualEntries(residual), ", "))
} else {
err = fmt.Errorf(Conf.Language(387), p, err.Error())
}
return
}
time.Sleep(100 * time.Millisecond)
}
return
}
// describeResidualEntries 返回仍然存在的残留条目描述(含目录),最多 3 项。
func describeResidualEntries(entries []string) (ret []string) {
sort.Strings(entries)
for _, entry := range entries {
if 3 == len(ret) {
ret = append(ret, "...")
breakView on GitHub (pinned to 9f775e8a12)