{"record":{"id":"08b69564b5679abf","repo":"can1357/oh-my-pi","slug":"symbol-symbol-not-found-on-line-linenumber","errorCode":null,"errorMessage":"Symbol \"${symbol}\" not found on line ${lineNumber}","messagePattern":"Symbol \"(.+?)\" not found on line (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/lsp/utils.ts","lineNumber":709,"sourceCode":"\tconst occurrence = Math.max(1, Number.parseInt(match[2], 10));\n\treturn { symbol: match[1], occurrence };\n}\n\nexport async function resolveSymbolColumn(filePath: string, line: number, symbolSpec?: string): Promise<number> {\n\tconst lineNumber = Math.max(1, line);\n\ttry {\n\t\tconst fileText = await Bun.file(filePath).text();\n\t\tconst lines = fileText.split(\"\\n\");\n\t\tconst targetLine = lines[lineNumber - 1] ?? \"\";\n\t\tif (!symbolSpec) {\n\t\t\treturn firstNonWhitespaceColumn(targetLine);\n\t\t}\n\n\t\tconst { symbol, occurrence } = parseSymbolSpec(symbolSpec);\n\t\tconst exactIndexes = findSymbolMatchIndexes(targetLine, symbol);\n\t\tconst fallbackIndexes = exactIndexes.length > 0 ? exactIndexes : findSymbolMatchIndexes(targetLine, symbol, true);\n\t\tif (fallbackIndexes.length === 0) {\n\t\t\tthrow new Error(`Symbol \"${symbol}\" not found on line ${lineNumber}`);\n\t\t}\n\t\tif (occurrence > fallbackIndexes.length) {\n\t\t\tthrow new Error(\n\t\t\t\t`Symbol \"${symbol}\" occurrence ${occurrence} is out of bounds on line ${lineNumber} (found ${fallbackIndexes.length})`,\n\t\t\t);\n\t\t}\n\t\treturn fallbackIndexes[occurrence - 1];\n\t} catch (error) {\n\t\tif (isEnoent(error)) {\n\t\t\tthrow new Error(`File not found: ${filePath}`);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nexport async function readLocationContext(filePath: string, line: number, contextLines = 1): Promise<string[]> {\n\tconst targetLine = Math.max(1, line);\n\tconst surrounding = Math.max(0, contextLines);","sourceCodeStart":691,"sourceCodeEnd":727,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/lsp/utils.ts#L691-L727","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-read the file and supply the current line number where the symbol appears.","Verify spelling and casing of the symbol text matches the source line exactly (or as a substring the fallback matcher accepts).","Use `symbol#N` only after confirming the symbol occurs on that line.","Drop the `symbol` param if you can supply an exact character position instead (non-project-aware path)."],"exampleFix":"// before\nawait lspTool.execute({ action: \"definition\", file: \"a.ts\", line: 42, symbol: \"myFunc\" }); // line 42 no longer has myFunc\n// after\nconst lines = (await Bun.file(\"a.ts\").text()).split(\"\\n\");\nconst line = lines.findIndex(l => l.includes(\"myFunc\")) + 1;\nawait lspTool.execute({ action: \"definition\", file: \"a.ts\", line, symbol: \"myFunc\" });","handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs/promises\";\nasync function lineContainsSymbol(file: string, line: number, symbol: string) {\n  const text = (await fs.readFile(file, \"utf8\")).split(\"\\n\")[line - 1] ?? \"\";\n  return text.includes(symbol);\n}\n// call only if await lineContainsSymbol(file, line, symbol)","typeGuard":null,"tryCatchPattern":"try {\n  return await lspTool.execute({ action: \"definition\", file, line, symbol });\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"not found on line\")) {\n    const line2 = await findLineContaining(file, symbol);\n    return lspTool.execute({ action: \"definition\", file, line: line2, symbol });\n  } throw err;\n}","preventionTips":["Re-read the file immediately before issuing position+symbol calls to avoid stale line numbers.","Use bare identifiers as they literally appear on the line (strip qualification).","Compute line numbers programmatically from current file content rather than cached positions."],"tags":["lsp","validation","source-text","stale-line"],"backgroundTag":"symbol-not-found-on-line","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}