can1357/oh-my-pi · error

vault://${opLabel} failed: ${detail}

Error message

vault://${opLabel} failed: ${detail}

What it means

`assertCliSuccess` wraps every Obsidian CLI subprocess invocation. If the spawned `obsidian` process exits non-zero, or exits 0 but printed a line starting with `Error:`, the CLI's own diagnostic (stderr, stdout, or the exit code) is surfaced as `vault://<op> failed: <detail>`. The error is a faithful pass-through of the Obsidian CLI failure, not a parser bug in this library.

Source

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

	if (bin) return bin;
	throw missingBinaryError();
}

function cliReportedError(result: ObsidianSpawnResult): string | undefined {
	const stderr = result.stderr.trim();
	if (stderr.startsWith("Error:")) return stderr;
	const stdout = result.stdout.trim();
	if (stdout.startsWith("Error:")) return stdout;
	return undefined;
}

function assertCliSuccess(opLabel: string, result: ObsidianSpawnResult): void {
	const reportedError = cliReportedError(result);
	if (result.exitCode === 0 && !reportedError) return;
	const stderr = result.stderr.trim();
	const stdout = result.stdout.trim();
	const detail = reportedError || stderr || stdout || `obsidian exited with code ${result.exitCode}`;
	throw new Error(`vault://${opLabel} failed: ${detail}`);
}

function parseVaultDirectory(stdout: string): Map<string, string> {
	const vaults = new Map<string, string>();
	for (const line of stdout.split(/\r?\n/)) {
		const trimmed = line.trimEnd();
		if (!trimmed) continue;
		const tab = trimmed.indexOf("\t");
		if (tab <= 0) continue;
		const name = trimmed.slice(0, tab);
		const vaultPath = trimmed.slice(tab + 1).trim();
		if (!name || !vaultPath) continue;
		vaults.set(name, path.resolve(vaultPath));
	}
	return vaults;
}

function parseActiveVaultPath(stdout: string): string {

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the `detail` suffix — it is the Obsidian CLI's own error; fix the underlying cause it names.
  2. Run `vault://_/` (list vaults) and confirm the vault name in your URL matches an existing vault.
  3. Update the Obsidian app/CLI to a version supporting the subcommand (e.g. `base:query`, `search:context`).
  4. Enable the required core plugins (Daily notes for `daily`, Bases for `base`) and retry.
  5. If the CLI is transiently failing, retry the operation after confirming Obsidian is running.

Example fix

// before
const res = await handler.resolve(parseInternalUrl("vault://OldName/?op=daily"));
// vault://daily failed: vault "OldName" not found
// after: discover the actual vault name first
const vaults = await handler.resolve(parseInternalUrl("vault://_/"));
const res = await handler.resolve(parseInternalUrl(`vault://${encodeURIComponent(correctName)}/?op=daily`));
Defensive patterns

Strategy: retry

Validate before calling

// Before invoking, verify preconditions the CLI depends on:
const vaults = await handler.resolve(parseInternalUrl("vault://_/")); // throws a clear error if CLI/vaults unavailable
// confirm the vault name exists in vaults.textContent before targeting vault://<Name>/...

Type guard

function isCliFailure(err: unknown): err is Error & { message: string } {
  return err instanceof Error && /^vault:\/\/.+ failed: /.test(err.message);
}

Try / catch

try {
  const res = await handler.resolve(parseInternalUrl(url));
} catch (err) {
  if (isCliFailure(err)) {
    const detail = err.message.replace(/^vault:\/\/.+ failed: /, "");
    logger.warn("obsidian cli failed", { url, detail });
    // retry once for transient failures; otherwise surface `detail` to the user
  } else throw err;
}

Prevention

When it happens

Trigger: #runCli / #loadVaultDirectory / #resolveVaultRoot / #vaultInfo spawn the Obsidian CLI and it fails: vault not found for the requested ref, daily-notes plugin not configured, Obsidian CLI too old and not accepting the subcommand, vault locked/unavailable, or the CLI prints `Error: ...` on stdout/stderr.

Common situations: Referencing a vault name that no longer exists or was renamed; Obsidian not running / CLI plugin version mismatch; daily notes core plugin disabled so `daily`/`daily-path` fail; transient Obsidian crashes or timeout kills (30s default) reported as a non-zero exit.

Related errors


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