LSP: documentSymbol / hover / goToDefinition always return empty; workspaceSymbol works

Resolved 💬 5 comments Opened Mar 9, 2026 by apmantza Closed Apr 6, 2026

Summary

All document-level LSP operations return empty results for all files in a TypeScript project. Only workspaceSymbol works.

Broken: documentSymbol, hover, goToDefinition, goToImplementation, findReferences, prepareCallHierarchy, incomingCalls, outgoingCalls
Working: workspaceSymbol

Environment

  • OS: Windows 11 Pro 10.0.26200
  • Shell: Git Bash
  • Claude Code model: claude-sonnet-4-6
  • Plugin: typescript-lsp@claude-plugins-official: true
  • typescript-language-server v5.1.3 (installed globally)
  • vtsls v0.3.0 (installed globally)

Repro

Any TypeScript project with a valid tsconfig.json. Example config:

{
  "compilerOptions": {
    "target": "ESNext",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/**/*"]
}

Test file src/core/task-runner.ts — non-empty, TaskRunner class at line 25, runOneTask method at line 83.

| Operation | Call | Result |
|---|---|---|
| documentSymbol | line 1, char 1 | "No symbols found" |
| hover | line 25, char 14 | (empty — tool ran without output) |
| goToDefinition | line 25, char 14 | "No definition found" |
| goToImplementation | line 25, char 14 | "No definition found" |
| findReferences | line 25, char 14 | "No references found" |
| prepareCallHierarchy | line 83, char 9 | "No call hierarchy item found" |
| incomingCalls | line 83, char 9 | "No call hierarchy item found" |
| outgoingCalls | line 83, char 9 | "No call hierarchy item found" |
| workspaceSymbol | (any) | ✅ Returns symbols correctly |

All document-level operations fail consistently across all files in the project, including simple files with no import errors (e.g. types.ts with only interface definitions).

Suspected root cause

All working operations (workspaceSymbol) use workspace-level requests that query the server's pre-built project index. All broken operations require textDocument/didOpen followed by a document-specific query. The LSP tool likely sends the document query without waiting for the server to signal it has finished processing the opened file (e.g. waiting for textDocument/publishDiagnostics), causing the server to return empty responses.

Secondary bug: workspaceSymbol mislabels file attribution

workspaceSymbol results group all symbols under the filePath argument header regardless of their actual source file. Passing filePath: "src/core/task-runner.ts" returns symbols correctly but labels them all as coming from src/core/engine.ts. The actual location.uri from the LSP response is ignored in grouping/display.

Impact

LSP is effectively non-functional for code navigation in this setup. Only workspace-wide symbol existence checks work. All targeted navigation (jump to definition, find callers, hover for type info) is unavailable.

View original on GitHub ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗