Skip to content

After upgrading Flutter to 3.29.3 image.toByteData throws empty Exception #171946

Closed

Description

@lighthead9288

Steps to reproduce

  1. Open Flutter app with flutter version 3.29 on Android emulator
  2. Add code which calls method image.toByteData multiple times in cycle
  3. It is reproducable on emulators and real devices; The bug appears not constantly - for instance, if you will have 10 attempts, it will run 8 times without any errors and it will throw an exception twice
    Part of Firebase Crashlytics log is below
        Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: Exception: 
       at _CustomZone.registerBinaryCallback(dart:async)
       at _RouteMapState._initMarkers(route_map.dart:134)
       at _RouteMapState.didUpdateWidget.<fn>(route_map.dart:75)
       at SchedulerBinding._invokeFrameCallback(binding.dart:1438)
       at SchedulerBinding.handleDrawFrame(binding.dart:1365)
       at SchedulerBinding._handleDrawFrame(binding.dart:1204)
  1. It was not reproducable on Flutter 3.27.3 or lower

Expected results

Method image.toByteData doesn't throw any exception, code after it is performing

Actual results

Method image.toByteData throws exception without any desciption

Code sample

Code sample
Future<BitmapDescriptor?> method() async {
  for (var index = 0; index < 3; index++) {
    await _generateMarker(index);
  }
}

Future<BitmapDescriptor?> _generateMarker(int index) async {
  final markerSize = 28;
  final iconSize = markerSize + (_strokeWidth * 2).round();
  final centerMarker = iconSize / 2;
  final radius = markerSize / 2;

  final backgroundPaint = Paint()..isAntiAlias = true;
  final pictureRecorder = ui.PictureRecorder();
  final canvas = Canvas(pictureRecorder);

  final textSpan = TextSpan(
    text: index.toString(),
    style: TextStyle(
      fontSize: 14,
      fontFamily: 'Inter',
      fontWeight: FontWeight.normal,
      height: 20 / 14,
      letterSpacing: 0,
      textBaseline: TextBaseline.alphabetic,
      decoration: TextDecoration.none,
      leadingDistribution: TextLeadingDistribution.even,
    ),
  );

  final textPainter =
      TextPainter(
        text: textSpan,
        textDirection: TextDirection.ltr,
      )..layout(
        minWidth: 0,
        maxWidth: iconSize.toDouble(),
      );
  backgroundPaint.color = Colors.green;

  canvas.drawCircle(Offset(centerMarker, centerMarker), radius, backgroundPaint);

  textPainter.paint(
    canvas,
    Offset(
      (iconSize - textPainter.width) / 2,
      (iconSize - textPainter.height) / 2,
    ),
  );

  final pic = pictureRecorder.endRecording();
  final img = await pic.toImage(iconSize.toInt(), iconSize.toInt());
  final byteData = await img.toByteData(format: ui.ImageByteFormat.png); //<-- Exception throws here
  final buffer = byteData?.buffer.asUint8List();

  if (buffer == null) return null;

  return BitmapDescriptor.fromBytes(buffer);
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
E/flutter (14843): [ERROR:flutter/lib/ui/painting/image_encoding_impeller.cc(195)] Failed to submit commands.
I/flutter (14843): [Reporter.error]:
I/flutter (14843): _Exception: Exception: 
I/flutter (14843): dart:async                                                                                 _CustomZone.registerBinaryCallback
I/flutter (14843): package:cargomart/src/presentation/screens/order_route_details/widgets/route_map.dart 134  _RouteMapState._initMarkers
I/flutter (14843): package:cargomart/src/presentation/screens/order_route_details/widgets/route_map.dart 75   _RouteMapState.didUpdateWidget.<fn>
I/flutter (14843): package:flutter/src/scheduler/binding.dart 1442                                            SchedulerBinding._invokeFrameCallback
I/flutter (14843): package:flutter/src/scheduler/binding.dart 1369                                            SchedulerBinding.handleDrawFrame
I/flutter (14843): package:flutter/src/scheduler/binding.dart 1208                                            SchedulerBinding._handleDrawFrame

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.32.5, on macOS 15.3 24D60 darwin-arm64 (Rosetta), locale ru-RU)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 16.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.1)
[✓] VS Code (version 1.83.1)
[✓] Connected device (3 available)
[✓] Network resources

• No issues found!

Activity

  1. darshankawar commented on Jul 10, 2025

    @darshankawar
    Member

    @lighthead9288 Please provide us minimal but complete runnable and reproducible code sample (ex: main.dart) that shows the reported behavior.

  2. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Jul 10, 2025
  3. lighthead9288 commented on Jul 11, 2025

    @lighthead9288
    Author

    flutter_create_markers_application.zip

    Steps to reproduce:

    1. Unzip this archive
    2. Open folder containing this flutter project, run command flutter pub get
    3. There are 2 screens in this project - first one has button 'Open', second one contains a widget with a geographic map. We draw marker points on the map widget at the second screen.
    4. Try to open and close second screen multiple times - if an attempt will lead to success, you will see 2 markers(green and red) on the map; if an attempt will be unsuccessfull - you will see a Snackbar and a specific text in debug console.
      The program throws an _Exception at this string:
    byteData = await img.toByteData(format: ui.ImageByteFormat.png)
    
  4. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Jul 11, 2025
  5. darshankawar commented on Jul 14, 2025

    @darshankawar
    Member

    Thanks for the repo @lighthead9288, I do see the error in the snackbar:

    Image

    But looking at the repo again, I see that there are some external library / implementations being used. Is it possible to narrow down the issue with google_maps_flutter and without external plugins ?

  6. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Jul 14, 2025
  7. github-actions commented on Aug 4, 2025

    @github-actions

    Without additional information, we are unfortunately not sure how to resolve this issue. We are therefore reluctantly going to close this bug for now.
    If you find this problem please file a new issue with the same description, what happens, logs and the output of 'flutter doctor -v'. All system setups can be slightly different so it's always better to open new issues and reference the related ones.
    Thanks for your contribution.

  8. github-actions commented on Aug 18, 2025

    @github-actions

    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 -v and a minimal reproduction of the issue.

  9. locked as resolved and limited conversation to collaborators on Aug 18, 2025
  10. jason-simmons commented on Sep 6, 2025

    @jason-simmons
    Member

    Reproduced this using the attached app on an Android emulator running Impeller/GLES.

    It reproduces more easily if I patch the app's _generatePointMarker to make repeated calls to Image.toByteData during the initial press of the "Open" button.

    The issue is caused by a race between the raster thread merger and the Impeller image encoder. The sequence is:

    • On the IO thread, a task calls EncodeImageAndInvokeDataCallback
      • EncodeImageAndInvokeDataCallback queues a task to the raster thread that will rasterize the image using Impeller.
    • On the raster thread, a task calls RasterThreadMerger::MergeWithLease
      • MergeWithLease merges the raster thread into the platform thread. Any pending raster tasks will be executed on the platform thread.
    • The raster task queued by EncodeImageAndInvokeDataCallback executes on the platform thread.
      • But at this point the platform thread may not have a current EGL context.
      • If the platform thread has no EGL context, then when the task submits an Impeller command buffer ReactorGLES::React will fail the CanReactOnCurrentThread check.
      • ImageEncodingImpeller::ConvertDlImageToSkImage will log the Failed to submit commands error, and the app's Image.toByteData call will throw an exception.

    The issue does not always happen because another raster task (such as an AcquireFrame) may run after the MergeWithLease and before the ImageEncodingImpeller task. If that task makes an EGL context current on the platform thread, then when the ImageEncodingImpeller task runs it will be able to execute GLES commands.

    Not sure what would be the best way to resolve this. It looks like the raster thread merger does not have a way to immediately make an EGL context current on the the merged thread.
    So instead ImageEncodingImpeller may need to use the SnapshotController::Delegate to activate an EGL context (similar to how the Skia image encoder implementation does this through SnapshotControllerSkia::ConvertToRasterImage)

    @chinmaygarde

  11. added
    engineflutter/engine related. See also e: labels.
    on Sep 8, 2025
  12. 6 remaining items

  13. added
    r: fixedIssue is closed as already fixed in a newer version
    on Sep 18, 2025
  14. github-actions commented on Oct 2, 2025

    @github-actions

    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 -v and a minimal reproduction of the issue.

  15. locked as resolved and limited conversation to collaborators on Oct 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P1High-priority issues at the top of the work listengineflutter/engine related. See also e: labels.found in release: 3.35Found to occur in 3.35found in release: 3.36Found to occur in 3.36has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-engineOwned by Engine teamtriaged-engineTriaged by Engine teamwaiting for PR to land (fixed)A fix is in flight

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions