-
Notifications
You must be signed in to change notification settings - Fork 30.1k
Description
Steps to reproduce
The crash occurs in FlutterPluginAppLifeCycleDelegate when the _delegates collection is modified (a delegate is added or removed) while it is being enumerated during a lifecycle event.
This typically happens if a plugin registers or unregisters a delegate inside a callback like application:didFinishLaunchingWithOptions:.
Steps to reproduce logic:
- A Flutter app starts on iOS.
FlutterPluginAppLifeCycleDelegatebegins iterating over_delegatesto forward a lifecycle event.- Inside the loop, one of the delegates (or a side effect) calls
addDelegate:orremoveDelegate:. - The
_delegatesNSHashTable is mutated. - The loop continues and crashes with
NSGenericExceptionbecause the collection was mutated during enumeration.
this crash has been introduced with 3.38.x and this PR : https://github.com/flutter/flutter/pull/176580/changes
On line 178,
for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in _delegates) { should be replaced by for (NSObject<FlutterApplicationLifeCycleDelegate>* delegate in [_delegates allObjects]) {
like the original code.
I'm opening a PR with Tests accordingly and this should be fixed in a 3.38.X (we're facing more than 200k crashes everyday)
Expected results
The app should handle delegate registration/deregistration gracefully during lifecycle events without crashing.
Actual results
The app crashes with the following exception:
Fatal Exception: NSGenericException
Collection <NSHashTable: ...> was mutated while being enumerated.
Stack trace:
Fatal Exception: NSGenericException
0 CoreFoundation 0xc5964 __exceptionPreprocess
1 libobjc.A.dylib 0x31814 objc_exception_throw
2 CoreFoundation 0x14e5dc +[__NSFastEnumerationEnumerator allocWithZone:]
3 Flutter 0x3d66c -[FlutterPluginAppLifeCycleDelegate application:didFinishLaunchingWithOptions:isFallbackForScene:] + 178 (FlutterPluginAppLifeCycleDelegate.mm:178)
4 Flutter 0x3d214 -[FlutterPluginAppLifeCycleDelegate application:didFinishLaunchingWithOptions:] + 151 (FlutterPluginAppLifeCycleDelegate.mm:151)
5 Flutter 0x13090 -[FlutterAppDelegate application:didFinishLaunchingWithOptions:] + 54 (FlutterAppDelegate.mm:54)
6 Runner 0xcae4 AppDelegate.application(_:didFinishLaunchingWithOptions:) + 79 (AppDelegate.swift:79)
7 Runner 0xd2f0 @objc AppDelegate.application(_:didFinishLaunchingWithOptions:) (<compiler-generated>)
8 UIKitCore 0x1420384 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:]
9 UIKitCore 0x1421928 -[UIApplication _callInitializationDelegatesWithActions:forScene:payload:fromOriginatingProcess:]
10 UIKitCore 0x142594c -[UIApplication _runWithMainScene:transitionContext:completion:]
11 UIKitCore 0xa2dce8 -[_UISceneLifecycleMultiplexer completeApplicationLaunchWithFBSScene:transitionContext:]
12 UIKitCore 0xd8eb0 _UIScenePerformActionsWithLifecycleActionMask
13 UIKitCore 0xa2e564 __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke
14 UIKitCore 0xa2e0d8 -[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:]
15 UIKitCore 0xa2e37c -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]
16 UIKitCore 0xa2de08 -[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:]
17 UIKitCore 0xa39288 __186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke
18 UIKitCore 0xeabec4 +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:]
19 UIKitCore 0xd9cc8 _UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion
20 UIKitCore 0xa38f84 -[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]
21 UIKitCore 0x8781e4 __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.218
22 UIKitCore 0x877278 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:]
23 UIKitCore 0x877e50 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:]
24 UIKitCore 0x1424918 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:]
25 UIKitCore 0xed4cb4 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:]
26 FrontBoardServices 0x1e3ec __95-[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:]_block_invoke
27 FrontBoardServices 0x1e8a4 -[FBSScene _callOutQueue_maybeCoalesceClientSettingsUpdates:]
28 FrontBoardServices 0x1e204 -[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:]
29 FrontBoardServices 0x8cbcc __93-[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:]_block_invoke.349
30 FrontBoardServices 0x2bf64 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]
31 FrontBoardServices 0x48e04 -[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:]
32 FrontBoardServices 0x4a768 __92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke_2
33 FrontBoardServices 0x2bf64 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]
34 libdispatch.dylib 0x1b7fc _dispatch_client_callout
35 libdispatch.dylib 0x6bb4 _dispatch_block_invoke_direct
36 BoardServices 0x91d4 __BSSERVICEMAINRUNLOOPQUEUE_IS_CALLING_OUT_TO_A_BLOCK__
37 BoardServices 0x9054 BSServiceMainRunLoopSourceHandler
38 CoreFoundation 0x68f10 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
39 CoreFoundation 0x68e84 __CFRunLoopDoSource0
40 CoreFoundation 0x46acc __CFRunLoopDoSources0
41 CoreFoundation 0x1d6d8 __CFRunLoopRun
42 CoreFoundation 0x1ca6c _CFRunLoopRunSpecificWithOptions
43 GraphicsServices 0x1498 GSEventRunModal
44 UIKitCore 0x9ddf8 -[UIApplication _run]
45 UIKitCore 0x46e54 UIApplicationMain
46 UIKitCore 0x172938 -[UIScrollView contentInset]
47 Runner 0xdcf0 main (AppDelegate.swift)
48 ??? 0x193592e28 (Manquant)
...
Code sample
This is an issue within the iOS Engine embedding (FlutterPluginAppLifeCycleDelegate). It cannot be reproduced with pure Dart code.
To reproduce the crash, a native plugin must add or remove a delegate while the FlutterPluginAppLifeCycleDelegate is iterating over its delegates (e.g., during didFinishLaunchingWithOptions).
Here is the Objective-C unit test logic that reproduces the NSGenericException:
// 1. Define a delegate that mutates the list during execution
@interface MutatingDelegate : NSObject <FlutterApplicationLifeCycleDelegate>
@property(nonatomic, weak) FlutterPluginAppLifeCycleDelegate* container;
@end
@implementation MutatingDelegate
- (BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
// THIS CAUSES THE CRASH: Modifying the collection while it is being iterated
[self.container addDelegate:[[NSObject alloc] init]];
return YES;
}
@end
// 2. The Test Case
- (void)testCrashReproduction {
FlutterPluginAppLifeCycleDelegate* delegate = [[FlutterPluginAppLifeCycleDelegate alloc] init];
MutatingDelegate* mutatingDelegate = [[MutatingDelegate alloc] init];
mutatingDelegate.container = delegate;
[delegate addDelegate:mutatingDelegate];
// This line throws "Fatal Exception: NSGenericException"
// "Collection <NSHashTable> was mutated while being enumerated."
[delegate application:[UIApplication sharedApplication]
didFinishLaunchingWithOptions:nil];
}
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
Fatal Exception: NSGenericException
0 CoreFoundation 0xc5964 __exceptionPreprocess
1 libobjc.A.dylib 0x31814 objc_exception_throw
2 CoreFoundation 0x14e5dc +[__NSFastEnumerationEnumerator allocWithZone:]
3 Flutter 0x3d66c -[FlutterPluginAppLifeCycleDelegate application:didFinishLaunchingWithOptions:isFallbackForScene:] + 178 (FlutterPluginAppLifeCycleDelegate.mm:178)
4 Flutter 0x3d214 -[FlutterPluginAppLifeCycleDelegate application:didFinishLaunchingWithOptions:] + 151 (FlutterPluginAppLifeCycleDelegate.mm:151)
5 Flutter 0x13090 -[FlutterAppDelegate application:didFinishLaunchingWithOptions:] + 54 (FlutterAppDelegate.mm:54)
6 Runner 0xcae4 AppDelegate.application(_:didFinishLaunchingWithOptions:) + 79 (AppDelegate.swift:79)
7 Runner 0xd2f0 @objc AppDelegate.application(_:didFinishLaunchingWithOptions:) (<compiler-generated>)
8 UIKitCore 0x1420384 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:]
9 UIKitCore 0x1421928 -[UIApplication _callInitializationDelegatesWithActions:forScene:payload:fromOriginatingProcess:]
10 UIKitCore 0x142594c -[UIApplication _runWithMainScene:transitionContext:completion:]
11 UIKitCore 0xa2dce8 -[_UISceneLifecycleMultiplexer completeApplicationLaunchWithFBSScene:transitionContext:]
12 UIKitCore 0xd8eb0 _UIScenePerformActionsWithLifecycleActionMask
13 UIKitCore 0xa2e564 __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke
14 UIKitCore 0xa2e0d8 -[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:]
15 UIKitCore 0xa2e37c -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]
16 UIKitCore 0xa2de08 -[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:]
17 UIKitCore 0xa39288 __186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke
18 UIKitCore 0xeabec4 +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:]
19 UIKitCore 0xd9cc8 _UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion
20 UIKitCore 0xa38f84 -[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]
21 UIKitCore 0x8781e4 __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.218
22 UIKitCore 0x877278 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:]
23 UIKitCore 0x877e50 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:]
24 UIKitCore 0x1424918 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:]
25 UIKitCore 0xed4cb4 -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:]
26 FrontBoardServices 0x1e3ec __95-[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:]_block_invoke
27 FrontBoardServices 0x1e8a4 -[FBSScene _callOutQueue_maybeCoalesceClientSettingsUpdates:]
28 FrontBoardServices 0x1e204 -[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:]
29 FrontBoardServices 0x8cbcc __93-[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:]_block_invoke.349
30 FrontBoardServices 0x2bf64 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]
31 FrontBoardServices 0x48e04 -[FBSWorkspaceScenesClient _callOutQueue_sendDidCreateForScene:transitionContext:completion:]
32 FrontBoardServices 0x4a768 __92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke_2
33 FrontBoardServices 0x2bf64 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:]
34 libdispatch.dylib 0x1b7fc _dispatch_client_callout
35 libdispatch.dylib 0x6bb4 _dispatch_block_invoke_direct
36 BoardServices 0x91d4 __BSSERVICEMAINRUNLOOPQUEUE_IS_CALLING_OUT_TO_A_BLOCK__
37 BoardServices 0x9054 BSServiceMainRunLoopSourceHandler
38 CoreFoundation 0x68f10 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
39 CoreFoundation 0x68e84 __CFRunLoopDoSource0
40 CoreFoundation 0x46acc __CFRunLoopDoSources0
41 CoreFoundation 0x1d6d8 __CFRunLoopRun
42 CoreFoundation 0x1ca6c _CFRunLoopRunSpecificWithOptions
43 GraphicsServices 0x1498 GSEventRunModal
44 UIKitCore 0x9ddf8 -[UIApplication _run]
45 UIKitCore 0x46e54 UIApplicationMain
46 UIKitCore 0x172938 -[UIScrollView contentInset]
47 Runner 0xdcf0 main (AppDelegate.swift)
48 ??? 0x193592e28 (Manquant)
Flutter Doctor output
Doctor output
Waiting for another flutter command to release the startup lock...
[✓] Flutter (Channel stable, 3.38.7, on macOS 26.2 25C56 darwin-arm64, locale fr-FR) [1 159ms]
• Flutter version 3.38.7 on channel stable at /Users/maxime_pontoire/fvm/versions/3.38.7
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 3b62efc2a3 (4 weeks ago), 2026-01-13 13:47:42 -0800
• Engine revision 78fc3012e4
• Dart version 3.10.7
• DevTools version 2.51.1
• Pub download mirror https://artifact.socrate.vsct.fr/artifactory/api/pub/all-pub
• Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop,
enable-android, enable-ios, cli-animations, enable-native-assets, omit-legacy-version-file,
enable-lldb-debugging
[✗] Android toolchain - develop for Android devices [1 105ms]
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/to/macos-android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✓] Xcode - develop for iOS and macOS (Xcode 26.2) [2,3s]
• Xcode at /Applications/Xcode.app/Contents/Developer
• Build 17C52
• CocoaPods version 1.16.2
[✓] Chrome - develop for the web [13ms]
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Connected device (4 available) [6,5s]
• eMxPi’s iPhone (wireless) (mobile) • 00008130-00063DDA2E04001C • ios • iOS
26.3 23D127
• iPhone + Watch (mobile) • A2B07733-85AB-4812-BFD2-1822DB74E7CF • ios •
com.apple.CoreSimulator.SimRuntime.iOS-26-2 (simulator)
• macOS (desktop) • macos • darwin-arm64 •
macOS 26.2 25C56 darwin-arm64
• Chrome (web) • chrome • web-javascript •
Google Chrome 145.0.7632.46
[✓] Network resources [326ms]
• All expected network resources are available.