can1357/oh-my-pi · error

Symbol "${symbol}" not found on line ${lineNumber}

Error message

Symbol "${symbol}" not found on line ${lineNumber}

What it means

resolveSymbolColumn reads the target line from the file and locates the symbol text to compute the character column, first with exact matching, then with a looser fallback. If the symbol appears nowhere on that line, it throws this error so callers get a precise message instead of a column-0 guess.

Source

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

	const occurrence = Math.max(1, Number.parseInt(match[2], 10));
	return { symbol: match[1], occurrence };
}

export async function resolveSymbolColumn(filePath: string, line: number, symbolSpec?: string): Promise<number> {
	const lineNumber = Math.max(1, line);
	try {
		const fileText = await Bun.file(filePath).text();
		const lines = fileText.split("\n");
		const targetLine = lines[lineNumber - 1] ?? "";
		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);

View on GitHub (pinned to 9690622007)

Solutions

  1. Re-read the file and supply the current line number where the symbol appears.
  2. Verify spelling and casing of the symbol text matches the source line exactly (or as a substring the fallback matcher accepts).
  3. Use `symbol#N` only after confirming the symbol occurs on that line.
  4. Drop the `symbol` param if you can supply an exact character position instead (non-project-aware path).

Example fix

// before
await lspTool.execute({ action: "definition", file: "a.ts", line: 42, symbol: "myFunc" }); // line 42 no longer has myFunc
// after
const lines = (await Bun.file("a.ts").text()).split("\n");
const line = lines.findIndex(l => l.includes("myFunc")) + 1;
await lspTool.execute({ action: "definition", file: "a.ts", line, symbol: "myFunc" });
Defensive patterns

Strategy: validation

Validate before calling

import * as fs from "node:fs/promises";
async function lineContainsSymbol(file: string, line: number, symbol: string) {
  const text = (await fs.readFile(file, "utf8")).split("\n")[line - 1] ?? "";
  return text.includes(symbol);
}
// call only if await lineContainsSymbol(file, line, symbol)

Try / catch

try {
  return await lspTool.execute({ action: "definition", file, line, symbol });
} catch (err) {
  if (err instanceof Error && err.message.includes("not found on line")) {
    const line2 = await findLineContaining(file, symbol);
    return lspTool.execute({ action: "definition", file, line: line2, symbol });
  } throw err;
}

Prevention

When it happens

Trigger: Calling execute() with a `symbol` param whose text does not appear (even with fallback matching) on the given `line` of `file` — e.g. stale line numbers after the file changed, or a typo in the symbol name.

Common situations: Line numbers taken from an older read of the file that has since been edited; copying a qualified name (`Foo.bar`) that appears on the line only as `bar`; case/whitespace mismatch.

Related errors


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