Steps to reproduce
- Create a Flutter app with an iOS app extension (e.g., WidgetKit widget extension)
- Run
flutter run -v --flavor <flavor> on a physical iOS 17+ device
- Observe that LLDB sometimes attaches to the extension process instead of the main app
Expected results
LLDB should always attach to the main app process (e.g., MainApp[DEV]).
Actual results
LLDB intermittently attaches to the extension process (e.g., somethingExtension), causing flutter run to fail or behave incorrectly.
This is a race condition. When iOS launches both the main app and its extension, both processes appear in devicectl device info processes. Flutter picks the first match, which may be the extension.
Root cause
In packages/flutter_tools/lib/src/ios/core_devices.dart (around line 122-130), the process discovery uses .contains(installationURL) to match the launched process:
final IOSCoreDeviceRunningProcess? launchedProcess = processes
.where(
(IOSCoreDeviceRunningProcess process) =>
process.executable != null && process.executable!.contains(installationURL),
)
.firstOrNull;
The installationURL is the app bundle path, e.g.:
/private/var/containers/Bundle/Application/<UUID>/MainApp[DEV].app/
Both the main app and extension processes match this path because the extension lives inside the app bundle:
PID 4211 .../MainApp[DEV].app/PlugIns/somethingExtension.appex/...
PID 4212 .../MainApp[DEV].app/MainApp[DEV]
.firstOrNull picks whichever appears first in the process list. When the extension process has a lower PID (spawned first by iOS), it wins — and LLDB attaches to the wrong process.
Proposed fix
Filter out app extension processes (.appex) from the process matching:
final IOSCoreDeviceRunningProcess? launchedProcess = processes
.where(
(IOSCoreDeviceRunningProcess process) =>
process.executable != null &&
process.executable!.contains(installationURL) &&
!process.executable!.contains('.appex'),
)
.firstOrNull;
Environment
- Flutter 3.41.4 (stable)
- Xcode 16.3
- iOS 18.x physical device (wireless debugging)
- macOS 15.3 (arm64)
- App has WidgetKit extension embedded via "Embed Foundation Extensions" build phase
Code sample
Code sample
This bug requires a WidgetKit extension embedded in the app bundle, which cannot be set up via flutter create. The reproduction project was generated with Very Good CLI, then a WidgetKit widget extension was added through Xcode.
See the repository linked below for the full project and detailed root cause analysis:
https://github.com/Silfalion/small_test
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
Flutter Doctor output
Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.41.4, on macOS 26.3 25D125 darwin-arm64, locale en-DZ)
[!] Android toolchain - develop for Android devices (Android SDK version 36.1.0-rc1)
✗ Flutter requires Android SDK 36 and the Android BuildTools 28.0.3
To update the Android SDK visit https://flutter.dev/to/macos-android-setup for detailed instructions.
[✓] Xcode - develop for iOS and macOS (Xcode 26.3)
[✓] Chrome - develop for the web
[✓] Connected device (3 available)
[✓] Network resources
! Doctor found issues in 1 category.
Steps to reproduce
flutter run -v --flavor <flavor>on a physical iOS 17+ deviceExpected results
LLDB should always attach to the main app process (e.g.,
MainApp[DEV]).Actual results
LLDB intermittently attaches to the extension process (e.g.,
somethingExtension), causingflutter runto fail or behave incorrectly.This is a race condition. When iOS launches both the main app and its extension, both processes appear in
devicectl device info processes. Flutter picks the first match, which may be the extension.Root cause
In
packages/flutter_tools/lib/src/ios/core_devices.dart(around line 122-130), the process discovery uses.contains(installationURL)to match the launched process:The
installationURLis the app bundle path, e.g.:Both the main app and extension processes match this path because the extension lives inside the app bundle:
.firstOrNullpicks whichever appears first in the process list. When the extension process has a lower PID (spawned first by iOS), it wins — and LLDB attaches to the wrong process.Proposed fix
Filter out app extension processes (
.appex) from the process matching:Environment
Code sample
Code sample
This bug requires a WidgetKit extension embedded in the app bundle, which cannot be set up via
flutter create. The reproduction project was generated with Very Good CLI, then a WidgetKit widget extension was added through Xcode.See the repository linked below for the full project and detailed root cause analysis:
https://github.com/Silfalion/small_test
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]Flutter Doctor output
Doctor output