can1357/oh-my-pi · error
vault:// path resolution only supports plain filesystem path
Error message
vault:// path resolution only supports plain filesystem paths
What it means
`resolveVaultUrlToPath` maps a vault:// URL to a plain filesystem path, which is only defined for `fs-file` and `fs-dir` parse results. Op-based URLs (`file-op`, `vault-op`), `list-vaults`, and `vault-info` have no single filesystem equivalent, so the resolver rejects them with this error. Use the protocol handler's resolve() for those kinds instead.
Source
Thrown at packages/coding-agent/src/internal-urls/vault-protocol.ts:427
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);
ensureWithinRoot(realTarget, resolvedRoot);
} catch (error) {
if (!isEnoent(error)) throw error;View on GitHub (pinned to 9690622007)
Solutions
- Strip the `op` query parameter and resolve the underlying path portion of the URL.
- For op/vault-info/list URLs, use VaultProtocolHandler.resolve() to get an InternalResource instead of a filesystem path.
- Guard the call: parse the URL first with parseVaultUrl and only call resolveVaultUrlToPath when kind is fs-file or fs-dir.
Example fix
// before
const p = resolveVaultUrlToPath("vault://_/notes/idea.md?op=backlinks"); // throws
// after
const parsed = parseVaultUrl("vault://_/notes/idea.md?op=backlinks");
const p = parsed.kind === "fs-file" || parsed.kind === "fs-dir"
? resolveVaultUrlToPath(parsed)
: null; // handle ops via handler.resolve() instead Defensive patterns
Strategy: type-guard
Validate before calling
import { parseVaultUrl } from "./internal-urls/vault-protocol";
const parsed = parseVaultUrl(url);
if (parsed.kind !== "fs-file" && parsed.kind !== "fs-dir") {
throw new Error(`cannot resolve ${parsed.kind} to a filesystem path`);
}
const p = resolveVaultUrlToPath(parsed); Type guard
function isPlainFsVaultUrl(parsed: ReturnType<typeof parseVaultUrl>): parsed is Extract<ReturnType<typeof parseVaultUrl>, { kind: "fs-file" | "fs-dir" }> {
return parsed.kind === "fs-file" || parsed.kind === "fs-dir";
} Try / catch
try {
const p = resolveVaultUrlToPath(url);
} catch (err) {
if (err instanceof Error && err.message === "vault:// path resolution only supports plain filesystem paths") {
// route op/info/list URLs through handler.resolve() instead
} else throw err;
} Prevention
- parseVaultUrl first and branch on parsed.kind before choosing a resolver
- Strip ?op= parameters if you only need the underlying note/folder path
- Use handler.resolve() for op-based, vault-info, and list-vaults URLs
- Type helper signatures to accept only fs-file/fs-dir parse results
When it happens
Trigger: resolveVaultUrlToPath("vault://_/notes/idea.md?op=backlinks") (file-op), resolveVaultUrlToPath("vault://_/?op=search&q=x") (vault-op), resolveVaultUrlToPath("vault://_") (vault-info), or resolveVaultUrlToPath("vault://") (list-vaults).
Common situations: Passing arbitrary vault:// links (including op links embedded in notes) to a helper that expects plain note/folder paths; code that assumed every vault URL corresponds to a file on disk.
Related errors
- Unsupported vault:// file op: ${rawOp}
- Unsupported vault:// vault op: ${rawOp}
- vault://${op} requires '${name}' query parameter
- Provider delete URL must not embed an account credential
- Gemini Files API delete requires a valid file name
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/d50282d5c834dcc2.
Report an issue: GitHub.