can1357/oh-my-pi · error

Vault file not found: ${parsed.url}

Error message

Vault file not found: ${parsed.url}

What it means

#resolveFsTarget's realpath step wraps fs.promises.realpath(targetPath) and converts ENOENT failures into this friendly error carrying the original vault:// URL. Non-ENOENT errors are rethrown untouched. It means the referenced vault path (including any symlink chain) does not exist on disk.

Source

Thrown at packages/coding-agent/src/internal-urls/vault-protocol.ts:876

	async #readFile(
		parsed: Extract<ParsedVaultUrl, { kind: "fs-file" }>,
		context?: ResolveContext,
	): Promise<InternalResource> {
		const { root, targetPath } = await this.#resolveFsTarget(parsed, context);
		const parentDir = path.dirname(targetPath);
		try {
			const realParent = await fs.promises.realpath(parentDir);
			ensureWithinRoot(realParent, root);
		} catch (error) {
			if (!isEnoent(error)) throw error;
		}

		let realTargetPath: string;
		try {
			realTargetPath = await fs.promises.realpath(targetPath);
		} catch (error) {
			if (isEnoent(error)) {
				throw new Error(`Vault file not found: ${parsed.url}`);
			}
			throw error;
		}
		ensureWithinRoot(realTargetPath, root);
		const stat = await fs.promises.stat(realTargetPath);
		if (stat.isDirectory()) {
			return this.#listDir(parsed, context);
		}
		if (!stat.isFile()) {
			throw new Error(`vault:// URL must resolve to a file or directory: ${parsed.url}`);
		}

		const content = await Bun.file(realTargetPath).text();
		return {
			url: parsed.url,
			content,
			contentType: getContentType(realTargetPath),
			size: Buffer.byteLength(content, "utf-8"),

View on GitHub (pinned to 9690622007)

Solutions

  1. Create the missing file (the write path supports creating new files) or correct the URL path.
  2. Check the exact spelling and directory of the note in the vault.
  3. Re-register/refresh the vault path if the vault was moved (`obsidian vault info path` / vault list).
  4. Catch this error and treat the URL as a not-found resource if your code expects missing notes.

Example fix

// before
const res = await resolveInternalUrl("vault://_/old-name.md"); // renamed note
// after
const res = await resolveInternalUrl("vault://_/new-name.md");
Defensive patterns

Strategy: try-catch

Validate before calling

import * as fs from "node:fs/promises";
try {
  await fs.access(targetPath);
} catch {
  throw new Error(`Vault target does not exist yet: ${targetPath} (create it or fix the URL)`);
}

Try / catch

try {
  return await resolveInternalUrl(url);
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Vault file not found:")) {
    // treat as not-found resource or offer to create the file
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Resolving a vault:// URL whose target file does not exist — realpath fails with ENOENT — e.g. vault://_/notes/missing.md where no such note was ever created.

Common situations: Deleted or renamed notes referenced by stale links/URLs; typos in the path; vault moved to a different location so registered paths no longer resolve.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/af8dbaf35f5e8455. Report an issue: GitHub.