Repository navigation
[iOS] Crash NSGenericException in FlutterPluginAppLifeCycleDelegate (mutation while enumeration) #182361
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.
Activity
Fixes flutter#182361 Fix delegate copy on plugins init
Fixes flutter#182361 Fix delegate copy on plugins init
9 remaining items
flutter#182361 Fix delegate copy on plugins init (flutter#182362)
vashworth commentedon Feb 27, 2026
@eMxPi This is fixed on master and should be fixed in the next 3.41 stable and next beta release. However, I would like to understand more of how this is happening.
Have you migrated your app to UIScene lifecycle? Looking at the crash log, it seems like you have. Are you registering your plugins in
didInitializeImplicitFlutterEngineor inapplication: didFinishLaunchingWithOptions:?Can you provide a list of plugins you're using?
Add missing mutation-safe delegate iteration and use idomatic syntax (#…
eMxPi commentedon Mar 2, 2026
@vashworth we're currently working on the migration of the app. We're using several pubs, but the plugins we're registering "'manually" in the AppDelegate are Batch (batch_flutter) and background_locator_2
Add missing mutation-safe delegate iteration and use idomatic syntax (f…
flutter#182361 Fix delegate copy on plugins init (flutter#182362)
Add missing mutation-safe delegate iteration and use idomatic syntax (f…
[CP-stable] Update lifecycle event loops to be mutation-safe (#183125)
vashworth commentedon Mar 3, 2026
@eMxPi What do you mean you're "registering manually" in the AppDelegate? Could you provide a code sample?
eMxPi commentedon Mar 4, 2026
@vashworth i mean
flutter#182361 Fix delegate copy on plugins init (flutter#182362)
Add missing mutation-safe delegate iteration and use idomatic syntax (f…
github-actions commentedon Mar 18, 2026
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.flutter#182361 Fix delegate copy on plugins init (flutter#182362)