Have you checked for an existing issue?
Flutter Quill Version
11.5.1
Steps to Reproduce
- Embed
QuillEditor in a widget tree that temporarily changes the editor’s parent structure during async work (e.g. toggling between QuillEditor and IgnorePointer(child: QuillEditor) while loading).
- Trigger a focus/selection change during or after that rebuild (e.g. programmatic
replaceText / selection update when async work completes).
- Observe a scheduler callback exception in
_handleFocusChanged post-frame closure.
Expected results
Deferred focus/keyboard work should no-op safely if the editor state is no longer mounted.
Actual results
Post-frame callback runs on a disposed QuillRawEditorState and crashes when resolving keyboard appearance via context.
Additional Context
Details
Root cause
When dirty is true, _handleFocusChanged calls requestKeyboard() immediately and schedules _handleFocusChanged again via addPostFrameCallback without checking mounted. Other paths in the same file (e.g. _showCaretOnScreen) already guard with if (!mounted) return;; this path does not.
Proposed fix
- Guard
_handleFocusChanged with if (!mounted) return; at entry.
- Guard the post-frame callback before re-entering
_handleFocusChanged.
- Add early
mounted checks in requestKeyboard() and/or openConnectionIfNeeded() for defense in depth.
Impact
- Prevents background FlutterErrors / Crashlytics noise when editors are rebuilt or disposed during focus/selection updates.
- No intended change to normal typing, focus, or keyboard behavior when the widget remains mounted.
Stack trace:
State.context ← RawEditorStateTextInputClientMixin.createKeyboardAppearance ← RawEditorStateTextInputClientMixin.openConnectionIfNeeded ← QuillRawEditorState.requestKeyboard ← QuillRawEditorState._handleFocusChanged ← QuillRawEditorState._handleFocusChanged. (post-frame callback) ← SchedulerBinding.handleDrawFrame
Have you checked for an existing issue?
Flutter Quill Version
11.5.1
Steps to Reproduce
QuillEditorin a widget tree that temporarily changes the editor’s parent structure during async work (e.g. toggling betweenQuillEditorandIgnorePointer(child: QuillEditor)while loading).replaceText/ selection update when async work completes)._handleFocusChangedpost-frame closure.Expected results
Deferred focus/keyboard work should no-op safely if the editor state is no longer mounted.
Actual results
Post-frame callback runs on a disposed
QuillRawEditorStateand crashes when resolving keyboard appearance viacontext.Additional Context
Details
Root cause
When
dirtyis true,_handleFocusChangedcallsrequestKeyboard()immediately and schedules_handleFocusChangedagain viaaddPostFrameCallbackwithout checkingmounted. Other paths in the same file (e.g._showCaretOnScreen) already guard withif (!mounted) return;; this path does not.Proposed fix
_handleFocusChangedwithif (!mounted) return;at entry._handleFocusChanged.mountedchecks inrequestKeyboard()and/oropenConnectionIfNeeded()for defense in depth.Impact
Stack trace: State.context ← RawEditorStateTextInputClientMixin.createKeyboardAppearance ← RawEditorStateTextInputClientMixin.openConnectionIfNeeded ← QuillRawEditorState.requestKeyboard ← QuillRawEditorState._handleFocusChanged ← QuillRawEditorState._handleFocusChanged. (post-frame callback) ← SchedulerBinding.handleDrawFrame