Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[flutter_svg] Illegal argument in isolate message: object is unsendable - Library:'dart:async' Class: _Future #158835

Open
stuartmorgan opened this issue Nov 13, 2024 · 1 comment
Labels
p: flutter_svg The Flutter SVG drawing packages P2 Important issues not at the top of the work list package flutter/packages repository. See also p: labels.

Comments

@stuartmorgan
Copy link
Contributor

Imported from dnfield/flutter_svg#1099

Original report by @8symbols on Sep 2, 2024

If you provide a bundle argument to SvgPicture.asset and use Image.asset(...), then in profile and release modes the following exception will be thrown and svg won't be displayed:

Exception
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Invalid argument(s): Illegal argument in isolate message: object is unsendable - Library:'dart:async' Class: _Future@4048458 (see restrictions listed at `SendPort.send()` documentation for more information)
 <- _List len:8 (from dart:core)
 <- _Map len:1 (from dart:collection)
 <- Instance of 'PlatformAssetBundle' (from package:flutter/src/services/asset_bundle.dart)
 <- Instance of 'SvgAssetLoader' (from package:flutter_svg/src/loaders.dart)
 <- Context num_variables: 2 <- SvgLoader._load.<anonymous closure>.<anonymous closure> (from package:flutter_svg/src/loaders.dart)
 <- Context num_variables: 2 <- compute.<anonymous closure> (from package:flutter/src/foundation/_isolates_io.dart)
 <- resultPort in Instance of '_RemoteRunner<ByteData>' (from dart:isolate)

#0      Isolate._spawnFunction (dart:isolate-patch/isolate_patch.dart:398)
#1      Isolate.spawn (dart:isolate-patch/isolate_patch.dart:378)
#2      Isolate.run (dart:isolate:285)
#3      compute (package:flutter/src/foundation/_isolates_io.dart:18)
#4      compute (package:flutter/src/foundation/isolates.dart:82)
#5      SvgLoader._load.<anonymous closure> (package:flutter_svg/src/loaders.dart:154)
<asynchronous suspension>
#6      _VectorGraphicWidgetState._loadPicture.<anonymous closure> (package:vector_graphics/src/vector_graphics.dart:355)
<asynchronous suspension>
#7      _VectorGraphicWidgetState._loadPicture.<anonymous closure> (package:vector_graphics/src/vector_graphics.dart:369)
<asynchronous suspension>
#8      _VectorGraphicWidgetState._loadAssetBytes.<anonymous closure> (package:vector_graphics/src/vector_graphics.dart:402)
<asynchronous suspension>

That's because CachingAssetBundle stores futures in its fields, SvgAssetLoader stores bundle (if you provided one) and SvgLoader somehow sends it to other isolate in compute.

Debug build doesn't have this problem because it doesn't use other isolate.

Reproducible with Flutter 3.24.1 and flutter_svg: 2.0.10+1.

Sample app

assets/any_svg.svg and assets/any_png.png are literally any svg and png files respectively.

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';

void main() {
  runApp(
    const MaterialApp(
      home: Screen(),
    ),
  );
}

class Screen extends StatelessWidget {
  const Screen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          SvgPicture.asset(
            'assets/any_svg.svg',
            bundle: DefaultAssetBundle.of(context),
          ),
          Image.asset(
            'assets/any_png.png',
            width: 100.0,
            height: 100.0,
          ),
        ],
      ),
    );
  }
}

Problem can be fixed with the following change, but I don't sure how adequate it is.

Change that fixes problem
  Future<ByteData> _load(BuildContext? context) {
    final SvgTheme theme = getTheme(context);
    return prepareMessage(context).then((T? message) {
      return _compute<T>(
        message: message,
        xml: provideSvg(message),
        theme: theme,
        colorMapper: colorMapper,
      );
    });
  }

  static Future<ByteData> _compute<T>({
    required T? message,
    required String xml,
    required SvgTheme theme,
    required ColorMapper? colorMapper,
  }) {
    return compute((T? message) {
      return vg
          .encodeSvg(
            xml: xml,
            theme: theme.toVgTheme(),
            colorMapper: colorMapper == null
                ? null
                : _DelegateVgColorMapper(colorMapper),
            debugName: 'Svg loader',
            enableClippingOptimizer: false,
            enableMaskingOptimizer: false,
            enableOverdrawOptimizer: false,
          )
          .buffer
          .asByteData();
    }, message, debugLabel: 'Load Bytes');
  }
@stuartmorgan stuartmorgan added p: flutter_svg The Flutter SVG drawing packages package flutter/packages repository. See also p: labels. labels Nov 13, 2024
@jonahwilliams
Copy link
Member

Two things:

  1. we should always use Isolate.run and not conditionally parse. Need to verify performance.
  2. I don't know why we send the bundle to the isolate. maybe we can re-arrange this logic to only do the parsing in the isolate and leave the bundle on the UI thread.

@jonahwilliams jonahwilliams added the P2 Important issues not at the top of the work list label Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
p: flutter_svg The Flutter SVG drawing packages P2 Important issues not at the top of the work list package flutter/packages repository. See also p: labels.
Projects
None yet
Development

No branches or pull requests

2 participants