can1357/oh-my-pi · error
vault:// URL must resolve to a file or directory: ${parsed.u
Error message
vault:// URL must resolve to a file or directory: ${parsed.url} What it means
In the file-read path, after realpath and the directory branch, the handler requires stat.isFile(). Anything that is neither a directory nor a regular file — FIFOs, sockets, devices, etc. — triggers this error with the original URL. It is a defensive check so the handler never reads non-regular filesystem objects through vault://.
Source
Thrown at packages/coding-agent/src/internal-urls/vault-protocol.ts:886
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"),
sourcePath: realTargetPath,
};
}
async #writeFile(
parsed: Extract<ParsedVaultUrl, { kind: "fs-file" }>,
content: string,
context?: WriteContext,
): Promise<void> {
const { root, targetPath } = await this.#resolveFsTarget(parsed, context);View on GitHub (pinned to 9690622007)
Solutions
- Point the URL at a regular file or directory instead of the special file.
- Remove or relocate the symlink/special file from the vault if it was created accidentally.
- If you must access such a target, read it through a filesystem API outside vault://.
Example fix
// before
await resolveInternalUrl("vault://_/ipc.sock"); // special file -> throws
// after
await resolveInternalUrl("vault://_/ipc-config.md"); // regular file Defensive patterns
Strategy: type-guard
Validate before calling
import * as fs from "node:fs/promises";
const stat = await fs.stat(targetPath);
if (!stat.isFile() && !stat.isDirectory()) {
throw new Error(`${targetPath} is a special file; vault:// only reads regular files/directories`);
} Type guard
function isRegularOrDir(stat: fs.Stats): boolean {
return stat.isFile() || stat.isDirectory();
} Try / catch
try {
return await resolveInternalUrl(url);
} catch (err) {
if (err instanceof Error && err.message.includes("must resolve to a file or directory")) {
// skip this target; it is a socket/FIFO/device inside the vault
return null;
}
throw err;
} Prevention
- Audit vault directories for stray sockets/FIFOs and symlinks to special files.
- Skip non-regular entries when enumerating vault contents for resolution.
- Use lstat to detect suspicious symlinks before reading.
When it happens
Trigger: Resolving a vault:// URL whose target realpath is a special file (socket, FIFO, device node) rather than a regular file or directory, e.g. a symlink inside the vault pointing at a Unix socket.
Common situations: Vaults containing unexpected symlink targets into /tmp or /dev; stray special files created by other tooling inside the vault directory.
Related errors
- vault:// URL must resolve to a directory: ${parsed.url}
- Vault file not found: ${parsed.url}
- vault:// URL must resolve to a file: ${parsed.url}
- unknown filetype: {ft_debug}
- Is a directory
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/dd15c68d0f1cb51b.
Report an issue: GitHub.