flutter / flutter/flutter-intellij
IDE deadlocks permanently on project open when the Flutter SDK path is invalid (EDT blocked in FlutterModuleUtils.setFlutterModuleWithoutReload)
- Dominant language
- Java
- Stars
- 2k
- Forks
- 356
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 27
Description
## Summary
If a project's Flutter SDK path doesn't resolve, the plugin runs its "Fixing Flutter module configuration" path on project open and **deadlocks the IDE permanently** — no error, no timeout, process kill required.
`setFlutterModuleWithoutReload` calls `ProjectImpl.save()` from inside a write action on the EDT. That save dispatches document saving to a worker, then parks the EDT in a nested modal pump waiting for it; the worker must call back into the EDT to fire `beforeAllDocumentsSaving`. Circular wait, write lock held throughout.
Same EDT/`Semaphore` pattern as #9013 and #9055, different call site — those were `FlutterSettingsConfigurable`, this is project open. Both closed against 2026.1; this reproduces on 2026.2 / plugin 95.0.0.
The invalid SDK path is only the trigger; the deadlock is a re-entrancy bug and is not FVM-specific.
## Environment
Plugin 95.0.0 · IntelliJ IDEA 2026.2 (`IU-262.9437.185`) · JVM 25.0.3 · Windows 11 10.0.26200 · Flutter 3.47.1 stable / Dart 3.13.1
## Reproduction
1. Open a Flutter project whose configured SDK path doesn't resolve. Mine arose from FVM: `.fvm/flutter_sdk` symlinks to the SDK, and changing FVM's `cachePath` left it dangling. Any dangling path should do.
2. Open the project.
**Result:** permanent hang during project open.
**Expected:** an "SDK path is invalid" prompt, IDE responsive.
Deterministic — re-evaluated every open, so the IDE hangs every time until the path is fixed *outside* the IDE. This can lock a user out entirely, since fixing the path in-app requires Settings, which requires a responsive window.
## Evidence
Last lines in `idea.log`; nothing is logged after:
```
io.flutter.FlutterInitializer - Flutter module has been found for project:
io.flutter.FlutterInitializer - Fixing Flutter module configuration for
io.flutter.sdk.FlutterCommand - flutter.bat [--no-color, config, --machine]
```
**`AWT-EventQueue-0`** — holds the write lock, parked in a nested modal pump:
```
java.lang.Thread.State: WAITING
at java.desktop/java.awt.EventQueue.getNextEvent(EventQueue.java:561)
at com.intellij.ide.IdeEventQueue.getNextEvent(IdeEventQueue.kt:454)
at com.intellij.openapi.progress.impl.PlatformTaskSupportKt.pumpEventsForHierarchy(PlatformTaskSupport.kt:701)
at com.intellij.openapi.application.impl.ModalityKt.inModalContext(modality.kt:11)
at com.intellij.openapi.progress.impl.PlatformTaskSupport.runWithModalProgressBlockingInternal(PlatformTaskSupport.kt:373)
at com.intellij.platform.ide.progress.TasksKt.runWithModalProgressBlocking(tasks.kt:205)
at com.intellij.ide.impl.ProjectUtilKt.runUnderModalProgressIfIsEdt(ProjectUtil.kt:799)
at com.intellij.openapi.project.impl.ProjectImpl.save(ProjectImpl.kt:413)
at io.flutter.utils.FlutterModuleUtils.lambda$setFlutterModuleWithoutReload$4(FlutterModuleUtils.java:349)
at com.intellij.openapi.application.TransactionGuardImpl.runWithWritingAllowed(TransactionGuardImpl.java:246)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:1106)
```
**`DefaultDispatcher-worker-1`** — blocked calling back into the EDT:
```
java.lang.Thread.State: RUNNABLE
at com.intellij.util.concurrency.Semaphore.waitForUnsafe(Semaphore.java:126)
at com.intellij.util.concurrency.Semaphore.waitFor(Semaphore.java:114)
at com.intellij.openapi.application.impl.LaterInvocator.invokeAndWait(LaterInvocator.java:159)
at com.intellij.openapi.application.impl.ApplicationImpl.doInvokeAndWait(ApplicationImpl.java:630)
at com.intellij.openapi.application.impl.ApplicationImpl.invokeAndWait(ApplicationImpl.java:679)
at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl$FileDocumentManagerListenerBackgroundableBridge
.beforeAllDocumentsSaving(FileDocumentManagerImpl.java:1131)
at com.intellij.util.messages.impl.MessageBusImplKt.invokeListener(MessageBusImpl.kt:775)
at com.intellij.util.messages.impl.ToDirectChildrenMessagePublisher.publish(CompositeMessageBus.kt:156)
at com.intellij.openapi.fileEditor.impl.FileDocumentManagerImpl.saveDocuments(FileDocumentManagerImpl.java:267)
```
```
EDT ──── project.save() ────► worker (saveDocuments)
▲ │
│ invokeAndWait(beforeAllDocumentsSaving)
└────────────────────────────────────┘
```
The EDT's nested pump can't dispatch the worker's runnable — queued under a modality state the active modal context won't service. Neither thread progresses, so this never times out.
Full dumps available at `%LOCALAPPDATA%\JetBrains\IntelliJIdea2026.2\log\threadDumps-Dispatchers.Default-20260826-101607-IU-262.9437.185\` — happy to attach.
## Suggested direction
Don't call `ProjectImpl.save()` from inside a write action on the EDT — drop it and let the platform persist module changes, or schedule it after the write action completes. Given #9013/#9055 were the same pattern elsewhere, remaining `save()` / `invokeAndWait` calls reachable from EDT write actions may be worth an audit.
Separately, an unresolvable SDK path would ideally be detected before the repair path runs, so the failure is a message rather than a reconfiguration attempt.
## Related
- #9013 — IDE freezes permanently when applying a Flutter SDK path change in Settings — closed
- #9055 — Applying Flutter settings permanently deadlocks the EDT (leaked Semaphore permit) on IntelliJ 2026.1 — closed
---
*Note: this report was drafted with AI assistance. The stack traces, log excerpts, and version details are taken verbatim from thread dumps and logs on my machine, and the reproduction is one I hit in normal use.*
Contributor guide
Research direction
Start in FlutterModuleUtils.java at setFlutterModuleWithoutReload and reproduce the invalid SDK path project-open flow with the supplied IntelliJ and plugin versions. Compare the EDT/write-action behavior with the patterns described in #9013 and #9055. Done means project opening no longer deadlocks and an invalid SDK path produces the expected prompt or leaves the IDE responsive.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100