Once you’ve done the above, delete everything above this line.
Steps to reproduce
- Enable the CLI (Settings, General, Command line interface) and have the vault open.
- In a terminal at the vault root, create a source file:
obsidian create path="a.md" content=x
- Create a destination folder externally and immediately move the file into it (chained, so the move lands before the app registers the new folder):
mkdir r1 && obsidian move path="a.md" to="r1"
- Check enumeration:
obsidian files | grep a.md
obsidian folder path="r1"
and look for the file under r1 in the file explorer.
Control cases, both of which behave correctly:
# same steps, but let the folder register first
obsidian create path="b.md" content=x
mkdir r2 && sleep 2 && obsidian move path="b.md" to="r2"
# same steps, but create the folder through the app
obsidian create path="c.md" content=x
obsidian eval code="void app.vault.createFolder('r3')" && obsidian move path="c.md" to="r3"
Did you follow the troubleshooting guide? [Y/N]
Yes
Expected result
Either the move completes and the file is fully registered (visible in the file explorer, obsidian files, search), or the command fails with an error because the destination folder is not yet registered.
Actual result
The command exits 0 and prints Moved: a.md -> r1/a.md. The rename happens on disk and the internal path map updates:
obsidian file path="r1/a.md"returns file infoobsidian file path="a.md"returnsError: File "a.md" not found.
But the file is detached from the folder tree:
-
obsidian filesdoes not list it -
obsidian folder path="r1"reportsfiles 0 -
the file does not appear under
r1in the file explorer -
obsidian eval code="const f = app.vault.getFileByPath('r1/a.md'); JSON.stringify({path: f.path, parent: f.parent?.path ?? null})"returns
{"path":"r1/a.md","parent":null}
Previously resolved wikilinks to the file still open it, but everything that enumerates the tree (file explorer, quick switcher, search, Bases, graph) cannot see it. The folder itself registering a moment later (it shows up in obsidian folders and the file explorer within a couple of seconds) does not reconcile the already-orphaned file. The state persists until obsidian reload or an app restart, either of which rebuilds the tree and fully recovers the file.
Environment
SYSTEM INFO:
Obsidian version: 1.13.1
Installer version: 1.12.7
Operating system: Darwin Kernel Version 25.5.0: Tue Jun 9 22:28:34 PDT 2026; root:xnu-12377.121.10~1/RELEASE_ARM64_T6050 25.5.0
Login status: logged in
Language: en
Catalyst license: vip
Insider build toggle: on
Live preview: on
Base theme: adapt to system
Community theme: Primary 2.10.0
Snippets enabled: 0
Restricted mode: off
Plugins installed: 0
Plugins enabled: 0
RECOMMENDATIONS:
Custom theme and snippets: for cosmetic issues, please first try updating your theme and disabling your snippets. If still not fixed, please try to make the issue happen in the Sandbox Vault or disable community theme and snippets.
Additional information
Observed behavior suggests the move handler performs the disk rename and updates the flat path lookup without requiring the destination folder to exist in the vault tree; the parent attach silently no-ops, and the watcher registering the folder afterwards does not reconcile the orphan. The window between `mkdir` and registration is at least a few hundred ms (an interleaved `obsidian create` call does not consume it) but is closed by a 2 second sleep.
The practical trigger is scripted and agentic use, e.g. an agent running `mkdir` and `obsidian move` back to back, which is a headline use case for the CLI. Because the command reports success, callers have no way to detect the failure.
Workarounds found so far:
- `obsidian reload` recovers all orphaned files.
- Create folders through the app instead of mkdir: `obsidian eval code=“void app.vault.createFolder(‘r1’)”`.
- If a folder was created externally, wait until `obsidian folder path=“r1”` succeeds before moving into it.