siyuan-note/siyuan · error

Move notebook [ ] file [ ] failed

Error message

Move notebook [%s] file [%s] failed: %s

What it means

Box.Move renames a file/folder within a notebook via filelock.Rename and wraps failure in localized message 5 'Move notebook [%s] file [%s] failed: %s'. After a successful move it also cleans up an emptied ID-named parent dir. Because rename(2) semantics apply, an existing destination, a locked source, or a cross-device path will fail.

Solutions

  1. Check that newPath does not exist before moving (Box.Exist) and pick a unique name
  2. Close/stop other processes holding the source file (second kernel instance, sync agent, editor with the file open)
  3. Keep the notebook data on one filesystem; replace symlinked notebook dirs with real ones
Defensive patterns

Strategy: validation

Validate before calling

if (box.Exist(newPath)) throw new Error('destination already exists: ' + newPath);
if (!box.Exist(oldPath)) throw new Error('source missing: ' + oldPath);
box.Move(oldPath, newPath);

Prevention

When it happens

Trigger: POST /api/filetree/renameDoc / move paths where newPath already exists, the source .sy file is held by another process, or old and new paths resolve to different filesystems.

Common situations: Moving docs onto a destination name that collides with an existing doc; sync clients locking .sy files; workspace data split across mounts (e.g. symlinked notebook dirs).

Related errors


AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18). Data as JSON: /api/errors/ec33475702fbe466. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/box.go:466

	IncSync()
	return nil
}

func (box *Box) Move(oldPath, newPath string) error {
	if _, err := box.validateBoxPath(oldPath); err != nil {
		return err
	}
	if _, err := box.validateBoxPath(newPath); err != nil {
		return err
	}
	boxLocalPath := filepath.Join(util.DataDir, box.ID)
	fromPath := filepath.Join(boxLocalPath, oldPath)
	toPath := filepath.Join(boxLocalPath, newPath)

	if err := filelock.Rename(fromPath, toPath); err != nil {
		msg := fmt.Sprintf(Conf.Language(5), box.Name, fromPath, err)
		logging.LogErrorf("move [path=%s] in box [%s] failed: %s", fromPath, box.Name, err)
		return errors.New(msg)
	}

	if oldDir := path.Dir(oldPath); ast.IsNodeIDPattern(path.Base(oldDir)) {
		fromDir := filepath.Join(boxLocalPath, oldDir)
		if util.IsEmptyDir(fromDir) {
			filelock.Remove(fromDir)
		}
	}
	IncSync()
	return nil
}

func (box *Box) Remove(path string) error {
	if _, err := box.validateBoxPath(path); err != nil {
		return err
	}
	boxLocalPath := filepath.Join(util.DataDir, box.ID)
	filePath := filepath.Join(boxLocalPath, path)

View on GitHub (pinned to afa823b6b4)