JetBrains Said No Static Tool Catches This Freeze Bug. We Built One - And Found a Real Instance in Their Own Code.
DEV Community

JetBrains Said No Static Tool Catches This Freeze Bug. We Built One - And Found a Real Instance in Their Own Code.

The Problem

In September 2025 and again in March 2026, JetBrains' own Platform engineering team published two posts about a specific, recurring cause of IntelliJ IDE freezes: a background thread calling a blocking, non-cancellable read-lock API (ReadAction.compute(), ReadAction.run(), Application#runReadAction()) while a write action is pending.

The March post said it plainly: "many reports actually show problems in plugins that contain that single erroneous pattern" And just as plainly: there's no static tool that catches this today. Detection is manual - reading a thread dump after the freeze already happened in someone's real IDE.

The Tool

That's a strange gap for a static-analysis catalog to walk past. So I didn't. What I built - Background ReadAction Freeze Companion, a free, open-source IntelliJ Platform plugin that statically traces exactly this pattern.

  • It's interprocedural - it walks the real call graph from four recognized background-thread entry points to a blocking read-lock call, however many method calls deep.
  • It distinguishes the formally deprecated read-lock APIs from the one that isn't but is mechanically identical and explicitly discouraged in its own Javadoc.
  • A hit where the surrounding code already checks for cancellation gets downgraded, not suppressed.

GitHub: https://github.com/GapHunterLabs/background-readaction-freeze-companion

Validation Against Real Code

Validating it against the real thing - I checked it out against intellij-community itself.

First pass caught something for the right reason to not flag it: a real ReadAction.run() call in the Mercurial VCS integration that traces back to the EDT, not background - correctly held back.

The same pass surfaced a real gap in our own coverage (a background entry point we hadn't covered yet); I added it the same day.

Then, pointed at the Java test-execution module, it surfaced a clean, direct hit in SearchForTestsTask: nine lines apart, in the same method, one branch uses the cancellable pattern, the sibling branch - reachable through an ordinary "run tests before indexing finishes" interaction - uses the blocking one the Platform team's own post named.

I filed it: IJPL-254654, with the exact source reference and a suggested fix mirroring the pattern already used nine lines above it.

Why This, and Why Now

I read what a platform team said was a real, unsolved problem for them, built the tool that problem was asking for, and used it exactly the way it was designed - against real code, every finding hand-verified before it went anywhere.

Top comments (0)

Read on DEV Community ↗ ← Back to News

Comments

No comments yet. Start the discussion.