On Android vault.create intermittently fails to write file content

On Android, creating a file through vault.create occasionally fails silently, creating an empty file containing no data.

Steps to reproduce

On the Android app, open a fresh, “device storage” vault, with no Obsidian sync setup or plugins.
In the devtools console from chrome://inspect run a script like:

for (let i = 0; i < 2000; i++) {
    const file = `new-${i}.md`;
    const expected = "stuff";
    await app.vault.create(file, expected);
    const actual = await app.vault.read(app.vault.getAbstractFileByPath(file));
    if (actual != expected) {
        throw new Error(`${file} "${actual}" != "${expected}" WRITE FAILED`);
    } else {
        console.log(`${file} "${actual}" != "${expected}"`);
    }
}

This will pretty reliably fail with new-xx "" != "stuff".

It’s not some kind of caching issue on the read. The file is actually empty, stat will show size 0, and you can see the file is empty if you open the file outside of Obsidian.

It also doesn’t just happen if you are spamming the filesystem, even if you add delays you’ll still get failed writes eventually:

for (let i = 0; i < 2000; i++) {
    const file = `new-${i}.md`;
    await app.vault.create(file, "stuff");
    await sleep(1000);
    const stat = await app.vault.adapter.stat(file);
    if (stat.size == 0) {
        throw Error(`${file} ${stat.size} WRITE FAILED`);
    } else {
        console.log(`${file} ${stat.size}`);
    }
    await sleep(1000);
}

Using the adapter methods directly to create the file has the same issue:

for (let i = 0; i < 2000; i++) {
    const file = `new-${i}.md`;
    await app.vault.adapter.write(file, "stuff");
    const stat = await app.vault.adapter.stat(file);
    if (stat.size == 0) {
        throw Error(`${file} ${stat.size} WRITE FAILED`);
    } else {
        console.log(`${file} ${stat.size}`);
    }
}

And using the Capacitor writeFile method directly will do it as well, so maybe this is actually a Capacitor bug?

for (let i = 0; i < 2000; i++) {
    const file = `new-${i}.md`;
    await Capacitor.Plugins.Filesystem.writeFile({
        directory: null,
        path: `/storage/emulated/0/Documents/myvault/${file}`,
        data: "stuff",
        encoding: "utf8",
    });
    const stat = await app.vault.adapter.stat(file);
    if (stat.size == 0) {
        throw Error(`${file} ${stat.size} WRITE FAILED`);
    } else {
        console.log(`${file} ${stat.size}`);
    }
}

The bug does not happen if you use the “app storage” option when creating the vault. The issue only occurs when creating a file, modifying an existing file always succeeds reliably.

Did you follow the troubleshooting guide? [Y]

Expected result

Files should be created with correct content.

Actual result

Files are sometimes created with empty content, despite having content passed to the vault.create method.

Environment

The bug only seems to occur on Android, the desktop version does not have this problem. I’ve reproduced the bug on a real Android 11 Motorola device, and an emulated Android 16 Pixel 9. I can reproduce it on both Obsidian versions 1.5.8 and 1.8.10.

Debug info on the real Android device:

SYSTEM INFO:
	Operating system: android 11 (motorola motorola one 5G ace)
	Obsidian version: 1.8.10 (197)
	API version: v1.8.10
	Login status: not logged in
	Language: en
	Live preview: on
	Base theme: adapt to system
	Community theme: none
	Snippets enabled: 0
	Restricted mode: on

Thank you for this report. This is indeed very strange.