JetBrains plugin: DiagnosticTools listener fires on invalidated PSI from background project windows (regression of #37543)

Resolved 💬 2 comments Opened May 21, 2026 by jjnssko Closed Jun 20, 2026

Summary

The Claude Code JetBrains plugin's DiagnosticTools daemon listener accesses invalidated PSI elements from project windows other than the one whose daemon emitted the event. This produces SEVERE PluginExceptions in the IDE log, contributes to memory pressure, and was previously reported in #37543 (closed as stale by the bot without a fix). The suggested fix in that issue (a psiFile.isValid guard) does not appear to have been applied in plugin v0.1.14-beta.

Environment

  • IDE: PhpStorm 2026.1.2 (Build PS-261.24374.185)
  • Plugin: Claude Code [Beta] v0.1.14-beta (com.anthropic.code.plugin)
  • JDK: OpenJDK 25.0.2 (JetBrains)
  • OS: macOS (Darwin 25.5.0)
  • Setup: Three git worktrees of the same monorepo open as three separate PhpStorm projects simultaneously.

Reproduction

  1. Open three (or more) project windows of related projects in PhpStorm simultaneously — e.g., git worktrees of the same repo.
  2. Edit a file in one window so the PSI for that path becomes invalidated.
  3. Trigger a daemon-finished event in any of the windows (regular editing or background re-analysis is enough; no Cmd+\` needed, unlike #37543).

Observed

SEVERE exceptions in idea.log, originating in DiagnosticTools.kt:106:

SEVERE - #c.i.u.m.i.MessageBusImpl - Invalid PSI Element: class com.jetbrains.php.lang.psi.PhpFileImpl #PHP
because: file:///…/monorepo-jv-express-pack/backend/src/…/ForceCompleteOrderStatusValidator.php (invalid) is invalid

com.intellij.diagnostic.PluginException: Invalid PSI Element …
    at com.intellij.psi.util.PsiUtilCore.ensureValid(PsiUtilCore.java:526)
    at com.intellij.psi.impl.source.PsiFileImpl.getTextLength(PsiFileImpl.java:405)
    at com.intellij.psi.impl.source.PsiFileImpl.getTextRange(PsiFileImpl.java:411)
    at com.intellij.codeInsight.daemon.impl.FileStatusMap.getFileDirtyScope(FileStatusMap.java:241)
    at com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl.isErrorAnalyzingFinished(DaemonCodeAnalyzerImpl.java:713)
    at com.anthropic.code.plugin.mcp.tools.DiagnosticTools\$addTools\$1\$1\$1.daemonFinished(DiagnosticTools.kt:106)
    at com.intellij.codeInsight.daemon.DaemonCodeAnalyzer\$DaemonListener.daemonFinished(DaemonCodeAnalyzer.java:123)

Counts in my recent two log files:

  • idea.log (current session): 8 occurrences
  • idea.1.log (previous session): 87 occurrences

The invalidated PSI in the stack trace belongs to a project other than the currently focused window, indicating the listener is registered at application scope and doesn't filter or validate before calling isErrorAnalyzingFinished().

Impact

  1. Repeated SEVERE log spam (95 occurrences across two recent sessions).
  2. Plugin holds stale PSI references → contributes to memory pressure. In my session the IDE also emitted Low memory signal received and ran into a separate PHP Stub index corruption (SerializedStubTree.getStubIndicesValueMap must not return null) that triggered an app-wide Rebuild requested for index Stubs, causing all three open projects to reindex ~95k files each (~7 minutes of pegged CPU). I do not claim this plugin caused the stub corruption, but the listener bug worsens memory headroom for users who hit the JetBrains stub bug.
  3. The Plugin to blame: PHP blame attribution in the log is misleading — the bottom-of-stack frame is from this plugin, not the PHP plugin.

Suggested fix

Per #37543, guard the PSI access in DiagnosticTools.kt:106:

\\\kotlin
if (psiFile.isValid) {
daemonCodeAnalyzer.isErrorAnalyzingFinished(psiFile)
}
\
\\

Or filter the listener by project at registration so it only sees events from the project it was scoped to.

References

  • Closed-as-stale predecessor: #37543

View original on GitHub ↗

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