2 files changed
+37
lib/core/services/crash_report_service.dart
+25
@@ -233,6 +233,10 @@ class CrashReportService {
233
errorWidgetPayload: errorWidgetPayload,
234
);
235
236
+ if (isBenignFrameworkError(error, stack)) {
237
+ return report;
238
+ }
239
+
240
// The duplicate check must run before the report is recorded, otherwise
241
// the freshly added report matches itself and no crash would ever surface
242
// in the UI.
@@ -249,6 +253,27 @@ class CrashReportService {
253
return report;
254
}
255
256
+ /// Checks whether an error is a known non-fatal Flutter framework issue that
257
+ /// should not crash the app or show the crash fallback screen.
258
+ ///
259
+ /// Currently handled:
260
+ /// - flutter/flutter#192081: Concurrent modification during iteration in
261
+ /// `MultiSelectableSelectionContainerDelegate.handleClearSelection` when
262
+ /// clearing selection across scrollable elements (e.g. Markdown code blocks).
263
+ static bool isBenignFrameworkError(Object error, [StackTrace? stack]) {
264
+ final errorStr = error.toString();
265
+ final stackStr = stack?.toString() ?? '';
266
+
267
+ if (errorStr.contains('Concurrent modification during iteration') &&
268
+ (stackStr.contains('MultiSelectableSelectionContainerDelegate') ||
269
+ stackStr.contains('selectable_region.dart') ||
270
+ stackStr.contains('_ScrollableSelectionContainerDelegate'))) {
271
+ return true;
272
+ }
273
+
274
+ return false;
275
+ }
276
+
277
/// Clear the current crash so the app can re-render normally.
278
void clearCrash() {
279
_setCurrentCrash(null);
lib/main.dart
+12
@@ -23,6 +23,12 @@ Future<void> main() async {
23
// window, so the user sees only one crash screen per incident.
24
FlutterError.onError = (details) {
25
FlutterError.presentError(details);
26
+ if (CrashReportService.isBenignFrameworkError(
27
+ details.exception,
28
+ details.stack,
29
+ )) {
30
+ return;
31
+ }
32
crashReports.capture(
33
details.exception,
34
details.stack ?? StackTrace.current,
@@ -31,6 +37,9 @@ Future<void> main() async {
37
};
38
39
PlatformDispatcher.instance.onError = (error, stack) {
40
+ if (CrashReportService.isBenignFrameworkError(error, stack)) {
41
+ return true;
42
+ }
43
crashReports.capture(error, stack);
44
return true;
45
};
@@ -53,6 +62,9 @@ Future<void> main() async {
62
runApp(const CrashFallbackApp());
63
},
64
(error, stack) {
65
+ if (CrashReportService.isBenignFrameworkError(error, stack)) {
66
+ return;
67
+ }
68
CrashReportService.instance.capture(error, stack);
69
},
70
);