can1357/oh-my-pi · error · VaultDisabledError

vault:// is disabled. Enable it by setting `vault.enabled =

Error message

vault:// is disabled. Enable it by setting `vault.enabled = true` (Settings → Tools → Obsidian Vault).

What it means

Both `resolveVaultUrlToPath` and `VaultProtocolHandler.resolve` begin by checking `isVaultEnabled()`, which reads `vault.enabled` from settings (falling back to the schema default when settings are not initialized). If the feature flag is off, a `VaultDisabledError` with this exact message is thrown before any URL parsing. The vault:// protocol is opt-in.

Source

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

}

function findExistingAncestorSync(targetPath: string, rootPath: string): string {
	let current = targetPath;
	while (true) {
		ensureWithinRoot(current, rootPath);
		try {
			return fs.realpathSync(current);
		} catch (error) {
			if (!isEnoent(error)) throw error;
			const parent = path.dirname(current);
			if (parent === current) throw error;
			current = parent;
		}
	}
}

export function resolveVaultUrlToPath(input: string | InternalUrl): string {
	if (!isVaultEnabled()) throw new VaultDisabledError();
	const parsed = parseVaultUrl(input);
	if (parsed.kind !== "fs-file" && parsed.kind !== "fs-dir") {
		throw new Error("vault:// path resolution only supports plain filesystem paths");
	}

	const cachedRoot = getCachedVaultRoot(parsed.ref);
	if (!cachedRoot) {
		throw new Error(
			"vault:// path resolution requires a cached vault root; read vault:// first or use the write tool",
		);
	}

	const resolvedRoot = fs.realpathSync(cachedRoot);
	const targetPath = parsed.relativePath ? path.resolve(resolvedRoot, parsed.relativePath) : resolvedRoot;
	ensureWithinRoot(targetPath, resolvedRoot);

	try {
		const realTarget = fs.realpathSync(targetPath);

View on GitHub (pinned to 9690622007)

Solutions

  1. Enable the feature: set `vault.enabled = true` in settings (Settings → Tools → Obsidian Vault in the UI).
  2. Catch `VaultDisabledError` (check `error.name === "VaultDisabledError"`) and surface the enablement instructions to the user.
  3. In tests/SDK code, initialize settings with vault.enabled = true before resolving vault:// URLs, or use VaultProtocolHandler test hooks.

Example fix

// before
const p = resolveVaultUrlToPath("vault://_/notes/idea.md"); // throws VaultDisabledError
// after
if (!isVaultEnabled()) {
  await enableVaultInSettings(); // set vault.enabled = true
}
const p = resolveVaultUrlToPath("vault://_/notes/idea.md");
Defensive patterns

Strategy: type-guard

Validate before calling

import { isVaultEnabled } from "./internal-urls/vault-protocol";
if (!isVaultEnabled()) {
  throw new Error("Enable vault:// in Settings → Tools → Obsidian Vault (vault.enabled = true)");
}
const p = resolveVaultUrlToPath(url);

Type guard

function isVaultDisabledError(err: unknown): err is Error {
  return err instanceof Error && err.name === "VaultDisabledError";
}

Try / catch

try {
  const p = resolveVaultUrlToPath(url);
} catch (err) {
  if (isVaultDisabledError(err)) {
    ui.hint("vault:// is disabled — enable it in Settings → Tools → Obsidian Vault.");
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling resolveVaultUrlToPath() or handler.resolve() while the active settings profile has `vault.enabled = false` (or unset and the schema default is false), or in tests/SDK embedding where Settings.init has not run and the default disables vault.

Common situations: Fresh installs where the user never enabled the Obsidian integration; resolving vault:// links from notes on a machine with a different settings profile; CI/test environments without initialized settings.

Related errors


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