LSP: pyright cross-module symbol cache not invalidated after git operations (merge/pull/checkout)
Summary
Pyright's cross-module symbol cache stays stale after git operations (git merge, git pull, git checkout) modify imported source files. Diagnostics report "X is unknown import symbol" for symbols that genuinely exist in the imported module on disk. The LSP correctly re-analyzes the importing file's content (showing diagnostics that depend on the file's current state), but does not re-validate cross-module symbol references when the imported file changed via git.
Workaround: trust runtime tests during the affected window; ignore pyright's import-symbol diagnostics. Real fix would re-analyze chains when watched files change outside the harness's Edit/Write notifications.
Environment
- Claude Code: current as of 2026-04-18
- OS: Linux (WSL2)
- Plugin:
pyright-lsp@claude-plugins-official1.0.0 - Project: editable-installed Python package (
pip install -e .); imports resolve through venv's__editable__.<pkg>.pthpointing at<repo>/src/
Steps to Reproduce
- Start a Claude Code session in a Python project root.
- Add a new symbol (class/function/Protocol) to a module that's imported by an existing test file. Do this via a feature branch + PR + merge cycle:
- Create a branch, edit
src/<pkg>/<module>.pyto addclass NewProtocol. - Push, open PR, merge.
- In the same Claude Code session:
git fetch && git merge --ff-only origin/master.
- Open a test file that imports
NewProtocol:from <pkg>.<module> import NewProtocol. - Edit the test file (any change, even adding a comment) to trigger pyright re-analysis.
Expected Behavior
After step 2's merge, pyright should re-validate cross-module imports for any file that imports from the changed module. The from <pkg>.<module> import NewProtocol resolves correctly.
Actual Behavior
Pyright reports \"NewProtocol\" is unknown import symbol [reportAttributeAccessIssue]. The diagnostic persists across multiple Edit calls on the importing file. The LSP's hover operation on the symbol confirms: (import) NewProtocol: Unknown.
Crucially, pyright IS aware of the importing file's current content (it reports diagnostics that only exist post-merge — e.g., type errors on lines added in the merged PR). The cache miss is specifically on cross-module symbol resolution.
Restarting the Claude Code session resolves the issue (pyright re-analyzes from scratch).
Root Cause Analysis (hypothesis)
The pyright LSP server is started once at session start. Subsequent file changes are notified via textDocument/didChange only when the harness's Edit/Write tool runs. Git operations (git merge, git pull, git checkout) modify files on disk outside the harness's tool-call surface — pyright never receives a workspace/didChangeWatchedFiles or equivalent notification for those files.
The result: pyright's per-file content cache stays in sync (because the importing file's edits go through Edit), but the cross-module symbol table — which references modules whose content changed via git — goes stale.
This is structurally similar to #50224 (LSP behavior in worktree scenarios) but distinct — that issue is about diagnostics leaking across sessions; this is about a single session's LSP not seeing git-driven file changes within its own workspace.
Proposed Fix
Send workspace/didChangeWatchedFiles notifications to the LSP whenever a Bash tool call runs git commands that may modify tracked files (git merge, git pull, git checkout, git rebase, git reset, git restore, git apply, etc.). Or simpler: a coarse-grained \"after any git Bash command, mark the workspace dirty and re-analyze on next request.\"
Alternatively, expose an /lsp restart slash command (#39473 is a related FEATURE request) so users can manually clear the cache. Today there's no exposed mechanism to recover from the stale cache other than restarting the entire Claude Code session.
Impact
This bites any workflow that involves:
- Mid-session
git pullafter teammate changes land - Mid-session feature-branch merges (the multi-PR migration pattern is common)
- Mid-session
git checkoutbetween branches with diverged source code
In all three cases, pyright's diagnostics during the post-git work are noisy and unreliable — agents and humans must ignore them and rely on runtime tests for truth, which defeats the LSP's purpose during the most common collaborative-development scenarios.
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗