can1357/oh-my-pi · error

File not found: ${filePath}

Error message

File not found: ${filePath}

What it means

resolveSymbolColumn wraps its file read in try/catch; when the read fails with ENOENT (file does not exist), it rethrows as a plain, human-readable 'File not found' error naming the path instead of leaking the raw filesystem error.

Source

Thrown at packages/coding-agent/src/lsp/utils.ts:719

		if (!symbolSpec) {
			return firstNonWhitespaceColumn(targetLine);
		}

		const { symbol, occurrence } = parseSymbolSpec(symbolSpec);
		const exactIndexes = findSymbolMatchIndexes(targetLine, symbol);
		const fallbackIndexes = exactIndexes.length > 0 ? exactIndexes : findSymbolMatchIndexes(targetLine, symbol, true);
		if (fallbackIndexes.length === 0) {
			throw new Error(`Symbol "${symbol}" not found on line ${lineNumber}`);
		}
		if (occurrence > fallbackIndexes.length) {
			throw new Error(
				`Symbol "${symbol}" occurrence ${occurrence} is out of bounds on line ${lineNumber} (found ${fallbackIndexes.length})`,
			);
		}
		return fallbackIndexes[occurrence - 1];
	} catch (error) {
		if (isEnoent(error)) {
			throw new Error(`File not found: ${filePath}`);
		}
		throw error;
	}
}

export async function readLocationContext(filePath: string, line: number, contextLines = 1): Promise<string[]> {
	const targetLine = Math.max(1, line);
	const surrounding = Math.max(0, contextLines);
	try {
		const fileText = await Bun.file(filePath).text();
		const lines = fileText.split("\n");
		if (lines.length === 0) return [];

		const startLine = Math.max(1, targetLine - surrounding);
		const endLine = Math.min(lines.length, targetLine + surrounding);
		const context: string[] = [];
		for (let currentLine = startLine; currentLine <= endLine; currentLine++) {
			const content = lines[currentLine - 1] ?? "";

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the file exists at the given path and pass an absolute or project-relative path that resolves correctly.
  2. Re-check for recent renames/deletes (git status) and update the path.
  3. Run the tool from the correct working directory or pass a path relative to the project root.

Example fix

// before
await lspTool.execute({ action: "hover", file: "src/a.ts", line: 3 }); // wrong cwd
// after
await lspTool.execute({ action: "hover", file: "packages/app/src/a.ts", line: 3 });
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs/promises";
import * as path from "node:path";
async function assertFileExists(p: string) {
  const abs = path.resolve(p);
  await fs.access(abs, fs.constants.R_OK);
  return abs;
}
// await assertFileExists(params.file) before calling the tool

Try / catch

try {
  return await lspTool.execute({ action: "hover", file, line });
} catch (err) {
  if (err instanceof Error && err.message.startsWith("File not found:")) {
    // resolve against project root or prompt user for correct path
    return lspTool.execute({ action: "hover", file: path.join(projectRoot, file), line });
  } throw err;
}

Prevention

When it happens

Trigger: Calling any LSP tool action with a `file` path that does not exist on disk (after resolving relative to the project dir) — the readLocationContext/resolveSymbolColumn read hits ENOENT.

Common situations: Typos or wrong relative paths in tool params; file deleted or renamed after the agent read the plan; paths expressed against the wrong working directory (e.g. repo root vs package dir); Windows/POSIX path separator confusion.

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/87086b64e4217607. Report an issue: GitHub.