Skip to content

JetBrains plugin: IDE deadlocks on modal "Opening <file>" — Utils.maybeOpenFileInBackground calls FileEditorManager.openFile inside a write action #342

Description

@davidwilliamsAdyen

Bug report: Windsurf/Codeium JetBrains plugin deadlocks the IDE on "Opening "

Summary

com.codeium.intellij.diff.Utils.maybeOpenFileInBackground calls
FileEditorManager.openFile() from inside an explicit Application.runWriteAction { ... }
on the EDT. On modern IntelliJ platforms FileEditorManagerImpl.openFile performs
blockingWaitForCompositeFileOpen, which requires background read actions / PSI commits.
Those can never be granted while the EDT holds the write lock and is blocking on them,
so the IDE self-deadlocks behind the platform's modal "Opening " progress window.

The dialog is not cancellable in practice; the only recovery is force-killing the IDE.
All unsaved editor state is lost.

Environment

  • Android Studio 2026.1.2, build AI-261.25134.95.2612.15914620 (IntelliJ 261.x)
  • Windsurf/Codeium plugin 2.12.27 (identical code present in 2.12.26)
  • macOS

Reproduction

Have Cascade apply an edit to a file that is not the currently selected editor tab
(it may be open in a background tab — that is enough). The IDE hangs immediately.

Utils.maybeOpenFileInBackground returns early only when
FileEditorManager.getSelectedEditor().file == virtualFile. Any other case takes the
deadlocking path.

Evidence

idea.log, 2026-08-19 .. 2026-08-27: the line
#com.codeium.intellij.diff.Utils - Opening file: <path> occurs 8 times. Every single
occurrence is the last meaningful log line before a force-kill/restart.
Occurrences of
Attempting to open file that are not followed by Opening file (the early-return case)
are harmless.

Representative excerpt:

10:22:04,925 INFO - #com.codeium.intellij.diff.DiffView - diff view started for file:///.../IssuingPaymentCredentialsGenerator.kt
10:22:04,926 INFO - #com.codeium.intellij.diff.Utils   - Attempting to open file: /.../IssuingPaymentCredentialsGenerator.kt
10:22:04,927 INFO - #c.i.o.p.i.ProgressManagerImpl     - checkCancelled is invoked while write-action is pending. nonCancellable: false, hasProgressIndicator: false, hasContextJob: false, hasNoneBehavior: false, hasOnlyHooksBehavior: true, cancelled: false
10:22:04,927 INFO - #com.codeium.intellij.diff.Utils   - Opening file: /.../IssuingPaymentCredentialsGenerator.kt
10:22:05,079 INFO - #o.j.p.g.GradleManager             - Instructing gradle to use java from ...
10:22:07,074 INFO - #c.i.i.p.PluginManager             - Using cached broken plugins file
<no further application activity; only unrelated background HTTP pings>
10:23:35,208 INFO - STDOUT - Cmd+Q termination request.

Note this is NOT the previously-suspected "background write action starvation": the
WARN - #c.i.o.a.ApplicationManager - Cannot execute background write action in 10 seconds
message is entirely absent from the hanging session (last occurrence 2026-08-21, after which
the relevant platform flags were disabled). The deadlock reproduces regardless.

Offending code (from javap -p -c of codeium-2.12.27.jar)

maybeOpenFileInBackground$lambda$3 (pooled thread):

22: Application.runReadAction(Runnable)                       // lambda$3$lambda$0
44: invokedynamic  -> Runnable                                // lambda$3$lambda$2
49: Application.invokeLater(Runnable, ModalityState.nonModal())

maybeOpenFileInBackground$lambda$3$lambda$2 (EDT):

22: Project.isDisposed()          -> guard
31: VirtualFile.isValid()         -> guard
44: invokedynamic  -> Runnable                                // lambda$3$lambda$2$lambda$1
49: invokeinterface Application.runWriteAction(Runnable)V     // <-- BUG
54: callback.invoke(true)

maybeOpenFileInBackground$lambda$3$lambda$2$lambda$1:

33: invokevirtual FileEditorManager.openFile(VirtualFile, boolean)FileEditor[]

openFile is a UI/editor-lifecycle operation. It must not be invoked while holding the
write lock.

Suggested fix

Drop the runWriteAction wrapper — openFile is already being called on the EDT via
invokeLater, which is the correct and sufficient context:

// before
application.runWriteAction { fileEditorManager.openFile(virtualFile, false) }

// after
fileEditorManager.openFile(virtualFile, false)

Preferably use the platform's non-blocking API and invoke the callback on completion:

FileEditorManagerEx.getInstanceEx(project)
    .openFile(virtualFile, options = FileEditorOpenOptions(requestFocus = false))

or the coroutine variant openFile(file, options) from a plugin coroutine scope, so no
blocking wait happens on the EDT at all.

Local mitigation currently in use

A 2-byte, size-preserving in-place bytecode patch of
com/codeium/intellij/diff/Utils.class inside codeium-2.12.27.jar, swapping the
constant-pool index at the invokeinterface in maybeOpenFileInBackground$lambda$3$lambda$2
from #465 (Application.runWriteAction:(Ljava/lang/Runnable;)V) to #349
(Application.invokeLater:(Ljava/lang/Runnable;)V) — both already present in the pool with
identical descriptors, so the instruction length and stack shape are unchanged:

B9 01 D1 02 00   ->   B9 01 5D 02 00

This is obviously not something users should have to do; a released fix would be very welcome.

Relationship to existing issues

Searched Exafunction/codeium and Exafunction/CodeiumJetBrains. No existing issue
describes this deadlock. The closest is:

Both remain open with no maintainer reply, which suggests the underlying
openFile-inside-runWriteAction defect has never been triaged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions