fix: resolve SideEffectNotAllowedException in intention previews#11894
fix: resolve SideEffectNotAllowedException in intention previews#11894
Conversation
…n JetBrains intention previews DocumentChangeTracker and ActiveHandlerManager used Dispatchers.Main which schedules work via INVOKE_LATER. JetBrains forbids this during intention preview computation (autocomplete, inspections), throwing SideEffectNotAllowedException. Neither class requires EDT for its coroutine work, so switching to Dispatchers.Default resolves the issue. Fixes #9463, #8035
|
Docs Review: No documentation updates needed. This PR is an internal bug fix that changes coroutine dispatchers from |
Dispatchers.Default allows concurrent execution on a thread pool, which breaks thread-safety for shared mutable state that was previously serialized on the Main/EDT dispatcher. Using limitedParallelism(1) preserves single-threaded execution while still avoiding the SideEffectNotAllowedException from Dispatchers.Main.
There was a problem hiding this comment.
1 issue found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/listeners/ActiveHandlerManager.kt">
<violation number="1" location="extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/listeners/ActiveHandlerManager.kt:59">
P1: Switching this scope to `Dispatchers.Default` introduces unsynchronized cross-thread access to `ActiveHandlerManager` state, which can race handler activation/clearing against cursor-event processing.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| class ActiveHandlerManager(private val project: Project) : SelectionListener, CaretListener, DumbAware { | ||
|
|
||
| private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) | ||
| private val coroutineScope = CoroutineScope(Dispatchers.Default.limitedParallelism(1) + SupervisorJob()) |
There was a problem hiding this comment.
P1: Switching this scope to Dispatchers.Default introduces unsynchronized cross-thread access to ActiveHandlerManager state, which can race handler activation/clearing against cursor-event processing.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At extensions/intellij/src/main/kotlin/com/github/continuedev/continueintellijextension/listeners/ActiveHandlerManager.kt, line 59:
<comment>Switching this scope to `Dispatchers.Default` introduces unsynchronized cross-thread access to `ActiveHandlerManager` state, which can race handler activation/clearing against cursor-event processing.</comment>
<file context>
@@ -56,7 +56,7 @@ interface CursorMovementHandler {
class ActiveHandlerManager(private val project: Project) : SelectionListener, CaretListener, DumbAware {
- private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
+ private val coroutineScope = CoroutineScope(Dispatchers.Default.limitedParallelism(1) + SupervisorJob())
private var activeHandler: CursorMovementHandler? = null
private var isHandlingEvent = false
</file context>
There was a problem hiding this comment.
reviewed this closely and seems alright.
There was a problem hiding this comment.
Got it—thanks for checking.
Summary
SideEffectNotAllowedExceptionthrown during JetBrains intention preview computation (autocomplete, inspections)Dispatchers.MaintoDispatchers.DefaultinDocumentChangeTrackerandActiveHandlerManagercoroutine scopesDispatchers.Mainschedules work viaINVOKE_LATER, which JetBrains forbids during preview computation; neither class requires EDT for its coroutine workFixes #9463, #8035
Test plan
SideEffectNotAllowedExceptionSummary by cubic
Prevent SideEffectNotAllowedException in JetBrains intention previews by moving coroutine work off the EDT while keeping handlers single-threaded. Switched
Dispatchers.MaintoDispatchers.Default.limitedParallelism(1)to keep autocomplete and inspections stable and avoid race conditions.Dispatchers.Default.limitedParallelism(1)inDocumentChangeTrackerandActiveHandlerManagerto avoid INVOKE_LATER during previews and preserve serialized access to shared state.Written for commit 911240a. Summary will update on new commits.