Repository navigation
Description
Platform
Flutter Mobile Android
SDK versions
sentry_flutter/sentry/sentry_dio: 9.24.0- Flutter: 3.41.7 stable, release build (Impeller / Vulkan backend)
- Device: Samsung Galaxy A15 5G (SM-A156E), MediaTek MT6835 / Mali-G57, Android 15
Configuration
options.replay.sessionSampleRate = 0.03;
options.replay.onErrorSampleRate = 1.0;
// app wrapped in SentryWidget(child: app)What happened
A production user hit a native SIGABRT 3.000 s after MainActivity was destroyed. The crashing stack is an Impeller Vulkan texture teardown, reached from a picture.cc completion lambda being destroyed during a message-loop task flush:
android::Looper::pollOnce
fml::MessageLoopAndroid::OnEventFired (message_loop_android.cc:91)
fml::MessageLoopImpl::RunExpiredTasksNow (message_loop_impl.cc:139)
fml::MessageLoopImpl::FlushTasks (message_loop_impl.cc:122)
std::__fl::function<T>::operator= (function.h:968)
std::__fl::__function::__func<T>::destroy_deallocate (function.h:313)
const::lambda::~lambda (picture.cc:244)
sk_sp<T>::~sk_sp (SkRefCnt.h:256)
impeller::DlImageImpeller::~DlImageImpeller (dl_image_impeller.cc:84)
impeller::TextureVK::~TextureVK (texture_vk.cc:25)
impeller::TextureSourceVK::~TextureSourceVK (texture_source_vk.cc:11)
impeller::Attachment::~Attachment (formats.h:660)
...
abort
Lifecycle breadcrumbs immediately before it:
16:09:26.018 MainActivity paused
16:09:26.592 LOW_MEMORY (TRIM_MEMORY level 40)
16:09:26.601 MainActivity stopped
16:09:26.614 MainActivity destroyed
16:09:29.614 SIGABRT
Why I think this is the replay recorder
I can't attach a reproduction, so this is attribution by elimination — but the elimination is fairly tight:
-
Our app contains exactly one
RenderRepaintBoundary.toImage()call site, on a share-a-post screen. The affected user was a signed-out guest whose entire six-minute session was an onboarding flow; breadcrumbs show they never authenticated and never opened that screen. That path provably did not run. -
Nothing else in our code calls
toImage/toImageSync/Picture.toImage. -
That leaves the replay recorder as the only in-process producer, and it matches the stack exactly —
lib/src/screenshot/recorder.dart:- L84
final futureImage = renderObject.toImage(pixelRatio: capture.pixelRatio); - L223
finalImage = await picture.toImage(width, height);
Picture.toImageisPicture::RasterizeToImage, and the completion lambda inpicture.ccis what owns thesk_sp<DlImage>whose destruction runs~DlImageImpeller→~TextureVKin the stack above. - L84
Suspected race
ScheduledScreenshotRecorder.pause() / stop() (lib/src/replay/scheduled_recorder.dart L99–L120) set _status and stop the Scheduler, but they don't cancel or await a capture that is already in flight.
A capture that started just before the lifecycle transition still runs to completion on its own async chain: await futureImage → await image.toByteData() → canvas.drawImage → picture.toImage(width, height) → Screenshot(finalImage). Only then does _onImageCaptured observe _status != running and drop the frame.
The Dart-side Screenshot.dispose() does run in the finally, but releasing the image only posts the GPU-side texture release to the engine's message loop. By the time that task is flushed, the Activity and its Vulkan surface are gone, and destroying TextureVK against a dead context aborts inside the Mali driver. The TRIM_MEMORY 40 immediately beforehand plausibly accelerates the surface teardown and widens the window.
Suggested direction
On pause() / stop(), either await in-flight captures before returning (so the textures are released while the context is still alive), or refuse to start a capture once the app is no longer resumed. Dropping the finished frame at the end is enough for correctness of the replay itself, but not for the GPU resource it already allocated.
Caveats
Single event, no reproduction, and the native frames come from a release build. I'm reporting it because the code path lines up precisely and the failure mode (deferred GPU resource release racing surface teardown) looks structural rather than device-specific, even if this particular driver is what turns it into an abort.
Metadata
Metadata
Assignees
Projects
- StatusShow more project fieldsNo status
Activity
linear-code commentedon Jul 26, 2026
DART-448
lucas-zimerman commentedon Jul 29, 2026
Hi and thanks for opening this issue! We will investigate it and give you an update as soon as we get some news
buenaflor commentedon Aug 20, 2026
@lucas-zimerman it's possible that it is a Flutter issue as well: flutter/flutter#191168
We've merged a mitigation to minimize the window but it's not a full fix
For a full fix we should wait for flutter/flutter#192365
fix(flutter): Skip replay capture when app is not resumed
fix(flutter): Await in-flight replay capture on scheduler stop (#3935)
github-actions commentedon Sep 10, 2026
A PR addressing this issue has just been released 🚀
This issue was referenced by PR #3935, which was included in the 9.30.0 release.