Duplication Files with method fileManager.renameFile(file, newPath)

Steps to reproduce

Preparation:

  1. Create two folders (Folder1, Folder2).
  2. Insert a significant number of files into each folder (10 files per folder should suffice, but more is better).

Reproducing the Bug:

  1. Rename all files in the folders using the fileManager.renameFile(file, newPath) method (do not rename with an already used name) .
  2. Move a random file from Folder1 to Folder2 (or vice versa) using the same method.
  3. The bug typically occurs after 1 to 5 attempts.

Expected result

I expect the files to be moved correctly.

Actual result

Some random files are duplicated, resulting in files with both old and new paths.
Once it has occurred once, it tends to happen consistently without restarting or refreshing Obsidian.

Environment

SYSTEM INFO:
Obsidian version: v1.6.3
Installer version: v1.5.12
Operating system: Windows 10 Pro 10.0.19045
Login status: not logged in
Insider build toggle: off
Live preview: on
Base theme: adapt to system
Community theme: none
Snippets enabled: 0
Restricted mode: off
Plugins installed: 2
Plugins enabled: 1
1: Sample Plugin v1.0.0

(the only plugin enabled is the one I’m working on)

Additional information

This bug looks a lot like a bug already fixed : Note duplicates after a rename file or move file operation (possibly from Obsidian Sync)

I attempted to fix the issue by creating a function that moves the file and then checking if the file still exists at the old path using the getAbstractFileByPath(string) method. However, it returns null even when the file exists. This function works correctly in other parts of my code.

1 Like

thanks, we’ll look into it.

1 Like

Hello, can you please help clarify the steps to reproduce the issue?

So at this point all files have been moved from Folder1 into Folder2. Do you await each rename? Or are they performed concurrently?

The previous step removed all the files from Folder1 and moved them into Folder2. Are you now attempting to move a file again that has already been moved? Did you wait for the metadatacache to be updated before performing this move, or is it done immediately after step 1?

Thank you.

1 Like

Yeah sure!

Introduction:

Maybe I should introduce the purpose of this part of the plugin first.
I have created a new file explorer with a drag-and-drop feature, not only to move files from one folder to another but also to rearrange files within the same folder. There is also an automatic hierarchy.

A quick example within the same folder
If you have three files in the folder “4.2 titleFolder,” their names will start with “4.2.number”:

  • 4.2.1 title1
  • 4.2.2 title2
  • 4.2.3 title3

If you want the last file to become the first in your folder, you just drag and drop it to the first place. Then all files get renamed accordingly:

  • 4.2.1 title3
  • 4.2.2 title1
  • 4.2.3 title2

You can also drag and drop a file to another folder, and all files in the source folder will be renamed if needed, as will the files in the target folder.

Steps to reproduce:

  1. Create 2 folders (folder1 and folder2).
  2. Create 10 files in each of them.
  3. Now you can rename them as you wish. (For this plugin, I mainly change the number at the start of their titles).

My algorithm for moving a file to another folder looks like this:
// Make a place for the new file in the target folder
loop for all children of targetFolder

// Move the source file

// Reorganize the source folder
loop for all children of sourceFolder.

It works great if I do it a few times, but then I get one or multiple files duplicated. The more files there are in each folder, the sooner the bug will occur.

I do use await for the rename operation.
I don’t use threads currently, but I plan to use them soon to improve performance.
I don’t attempt to move a file that’s already been moved.

Thank you !

Thanks for the additional information.

I put together a toy plugin that rotates all the files in a folder, assuming the files are prefixed with n-. I used it to rotate a folder containing 40 files. I’ve done this a couple dozen times, but have been unable to reproduce.

What operating system are you on?

If possible, can you modify this plugin so that it reproduces the issue for you?
Thank you

import { Plugin } from 'obsidian';

export default class FileRotater extends Plugin {
	async onload() {
		this.addCommand({
			id: 'rotate-files',
			name: 'Rotate Files',
			callback: async () => {
				const srcFolder = this.app.vault.getFolderByPath('Folder1')
				if (!srcFolder) {
					console.log('folder not found');
					return
				}

				const children = [...srcFolder.children];
				for (let i = 0; i < children.length; i++) {
					const child = children[i];

					const currentNumber = /^([0-9]+)/.exec(child.name)[0];
					const newNumber = (parseInt(currentNumber) % children.length ) + 1;
					const newName = child.name.replace(/^[0-9]+/, `${newNumber}`);

					console.log(`Going to rename ${child.name} to ${newName}`);
					await this.app.fileManager.renameFile(child, `Folder1/${newName}`);
				}
			}
		});
	}
}


1 Like

Moved this convo to developers and api

I’m on Windows 10.
I will try to reproduce the bug today.
If I can or can’t , I’ll let you know anyway.
Have a nice day !

I was unable to reproduce the bug with the code you gave me, but after a long time, I have finally figured out what happens.

I have an event that triggers when a file is renamed. This event calls an async function that makes a copy of all the files and then reads the metadata of each one, modifying it if needed.

However, it looks like the trigger isn’t working properly (or as I thought it would).

So, if I move a big file, “file1,” the event is triggered, and it looks like sometimes the file is not moved yet. As a result, the function makes a copy of all files, and “file1” still appears in its old location. After the metadata is modified, this creates a copy of “file1” in its old location.

(By the way, this was an old idea, but with the trigger on, it makes all renames very slow because every time, all files are read.)