siyuan-note/siyuan · error
Move notebook [ ] file [ ] failed
Error message
Move notebook [%s] file [%s] failed: %s
What it means
Thrown inside moveDoc (kernel/model/file.go:1936) during a CROSS-notebook move when the sub-documents folder of the moved doc cannot be renamed on disk. The code first deletes an existing destination folder (filelock.Remove) then calls filelock.Rename(absFromPath, absToPath); if the OS rename fails, the raw error is wrapped into Conf.Language(5) ("Move notebook [%s] file [%s] failed: %s") together with a logging.LogErrorf entry, and the whole MoveDocs loop aborts at that path.
Solutions
- Read the trailing OS error embedded in the message (e.g. 'The process cannot access the file') — it identifies permission vs lock vs disk
- Close other SiYuan instances and sync/backup tools touching the workspace, then retry the move
- Check filesystem health: write permissions on data/<toBox>/, free disk space, path length limits
- Inspect kernel logs for the paired 'move [path=...] in box [...] failed' line to confirm which folder failed, and verify data/<fromBox> state afterwards; re-run /api/filetree/refreshFiletree if indexes look stale
Defensive patterns
Strategy: retry
Try / catch
err := model.MoveDocs(fromPaths, toBoxID, toPath, nil)
if err != nil && strings.Contains(err.Error(), Conf.Language(5)[:14]) /* 'Move notebook' wrapper */ {
logging.LogWarnf("cross-box folder move failed, likely transient file lock: %s", err)
// verify data/<fromBox> state, close offenders, then retry the single failed path
} Prevention
- Run only one kernel instance per workspace directory; extra instances defeat filelock assumptions
- Exclude the workspace data dir from antivirus real-time scanning and stagger backup jobs
- Prefer local filesystems over SMB/NFS for the workspace; renames there are the classic failure source
When it happens
Trigger: POST /api/filetree/moveDocs between two notebooks where data/<fromBox>/<docFolder> cannot be renamed to data/<toBox>/<newFolder>: destination locked by another process, permission denied, read-only or full disk, path length exceeded, or a race where another instance/sync wrote to the target between Remove and Rename.
Common situations: Two kernel instances (desktop + second workspace) opened on the same data directory; antivirus/indexer briefly locking files on Windows; data dir on a network drive (SMB/NFS) where rename is not atomic; leftover destination folder that could not be removed because a file inside was open.
Related errors
- rename path failed
- Conf.Language(5) formatted with box name, path and error
- copy data failed
- Export failed
- export source [ ] is not a regular file
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/da33e4373bc471af.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/file.go:1936
needMoveSubDocs := fromBox.Exist(fromFolder)
if needMoveSubDocs {
// 移动子文档文件夹
newFolder := path.Join(toFolder, tree.ID)
if isSameBox {
if err = fromBox.Move(fromFolder, newFolder); err != nil {
return
}
} else {
absFromPath := filepath.Join(util.DataDir, fromBox.ID, fromFolder)
absToPath := filepath.Join(util.DataDir, toBox.ID, newFolder)
if filelock.IsExist(absToPath) {
filelock.Remove(absToPath)
}
if err = filelock.Rename(absFromPath, absToPath); err != nil {
msg := fmt.Sprintf(Conf.Language(5), fromBox.Name, fromPath, err)
logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, fromBox.ID, err)
err = errors.New(msg)
return
}
}
}
newPath = path.Join(toFolder, tree.ID+".sy")
if isSameBox {
if err = fromBox.Move(fromPath, newPath); err != nil {
return
}
tree, err = filesys.LoadTree(fromBox.ID, newPath, luteEngine)
if err != nil {
return
}
moveTree(tree)View on GitHub (pinned to afa823b6b4)