[BUG] LSP goToDefinition drops definitions in git-ignored dependency folders (deps/, .venv, node_modules): reopen of #72594
Preflight Checklist
- [x] I have searched existing issues. This is the bug from #72594 and #76371, which a maintainer confirmed and said a fix was being looked at. Both were then auto-closed as stale, so I am opening a new issue as the bot asked.
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code available to me (2.1.280)
What's Wrong?
The LSP tool drops every goToDefinition, goToImplementation, findReferences and workspaceSymbol location whose path git check-ignore reports as ignored. For dependencies installed inside the project, the definition is always in an ignored folder: Elixir deps/, Python .venv/, JS node_modules/. Go-to-definition into a library therefore always reports:
No definition found. This may occur if the cursor is not on a symbol, or if the definition is in an external library not indexed by the LSP server.
The language server did return the location, so the hint points the wrong way. hover on the same position works, because it carries no URI, which makes this look like a language server bug.
Filtering ignored paths makes sense for findReferences and workspaceSymbol, where hits inside dependencies are noise. For goToDefinition and goToImplementation, the ignored location is usually the only correct answer.
What Should Happen?
goToDefinition and goToImplementation should return definitions in ignored paths. Alternatively, a setting could turn the filter off, or the tool could say that N results were hidden because they are git-ignored.
Steps to Reproduce
Elixir project with /deps/ in .gitignore, using the Dexter LSP plugin (dexter-lsp, Dexter 0.7.2):
- Run the
LSPtoolgoToDefinitiononEcto.Multi.new()orPhoenix.PubSub.broadcast(...)inlib/. - Result: "No definition found."
hoverat the same position returns the function's docs.workspaceSymbolwith queryEcto.Multi.newreturns "No symbols found in workspace."
Driving dexter lsp directly over stdio at the same positions returns the locations:
textDocument/definition => [{"uri":"file:///.../deps/ecto/lib/ecto/multi.ex","range":{"start":{"line":177,"character":0},...}}]
workspace/symbol => Ecto.Multi.new/0 file:///.../deps/ecto/lib/ecto/multi.ex
Controls in the same session:
Enum.group_byresolves, because the Elixir stdlib is in/nix/store, outside the repo, wheregit check-ignoredoes not apply.- Definitions in
lib/resolve.
Where it happens
In the 2.1.280 bundle, after sendRequest, the tool runs this when the operation is findReferences, goToDefinition, goToImplementation or workspaceSymbol:
if (F && Array.isArray(F) && (n.operation==="findReferences" || n.operation==="goToDefinition" || n.operation==="goToImplementation" || n.operation==="workspaceSymbol"))
// ... $p(locations, cwd) runs `git check-ignore <paths...>` in batches of 50
// and removes every location whose path is printed
No setting or environment variable guards it, so users have no workaround short of un-ignoring their dependency folders.
Is this a regression?
Yes. According to the maintainer comment on #72594, it started in 2.1.47 with the fix for #26051.
Claude Code Version
2.1.280 (Claude Code)
Operating System
macOS 26.6, arm64
Additional Information
Related: #72594 (.venv, confirmed and reproduced by a maintainer), #76371 (same filter hides .claude/worktrees/), #26051 (the original request to filter references).
3 Comments
Prior reports of this same filter, both confirmed by a maintainer and then auto-closed as stale: #72594 (
.venv) and #76371 (.claude/worktrees/). The filter was introduced for #26051.Please note that this issue is on its way to be auto-closed too, like the other ones.
To prevent this issue from getting stale, you would need to comment every time before the 14 days interval expires. See https://github.com/anthropics/claude-code/issues/87647 for more details and consider upvoting that for visibility.
The same filter has a second failure mode. It drops the project's own source code, not just dependencies, whenever the file sits in a nested git repository. The fix proposed here (stop filtering
goToDefinitionandgoToImplementation) would not cover it, so I'm adding it here instead of opening a duplicate.Cause. The filter runs
git check-ignorefrom the directory Claude Code was launched in. That applies the launch repository's ignore rules to every result, even when a file belongs to a different repository nested below it.Setup. This is a common multi-repo workspace: one small repo holds shared tooling, and the service repos are separate clones inside it.
Reproduce (Claude Code 2.1.283, WSL2, jdtls 1.61 via
jdtls-lsp@claude-plugins-official):cd ~/ws && claude..javafile underservice/.findReferenceson a class with 53 usages returns "No references found".goToDefinitionon a call to a method in the same file returns "No definition found".workspaceSymbolreturns "No symbols found in workspace".hover,documentSymbolandincomingCalls/outgoingCallswork, which points the investigation at jdtls instead of the tool.git check-ignore ~/ws/service/src/.../Foo.javaexits 0 from~/ws, because/*/matches. From~/ws/service, the repository that actually contains the file, it exits 1. Adding!/service/to~/ws/.gitignoremakes all four operations return correct results immediately, in the same session and without restarting the server.cd servicein the Bash tool does not help, because the filter uses the launch directory.Suggested fix, complementary to the one above. Judge each location by the repository that contains it:
git -C <dirname of file> check-ignore -- <file>, or group the locations bygit rev-parse --show-toplevel. A file inside a nested repository should never be filtered by an outer repository's.gitignore. The filter would still hidetarget/andnode_modules/, through the nested repository's own ignore rules.This is probably also why #76371 bit Claude Code's own worktrees: a worktree under
.claude/worktrees/is judged by the parent checkout's rules instead of its own.+1 to reporting "N results hidden (git-ignored)" rather than the current "not indexed / external library" hint. That hint made this look like a language server problem, and it is not one.