get_it icon indicating copy to clipboard operation
get_it copied to clipboard

Flutter web (only in release or profile) TypeError: Cannot read properties of null (reading 'pendingResult')

Open kosiarska opened this issue 3 years ago • 17 comments

I can run the app in android studio with no problem, when i run flutter run -d chrome --profile --dart-define=Dart2jsOptimization=O0 i get this error:

zrzut_ekranu_2021-12-17_o_17 50 14

kosiarska avatar Dec 17 '21 16:12 kosiarska

Have similar issue, which blocks my project running in production/profile image

bohdan1krokhmaliuk avatar Jan 17 '22 10:01 bohdan1krokhmaliuk

can you create a simple repro project, please?

escamoteur avatar Feb 02 '22 12:02 escamoteur

@escamoteur Hi, I created a simple project that reproduces the same issue for me (HERE: https://github.com/HKop/getit-issue) It started happening once we extracted some of the files to a "lib_common" library and wanted to use them in the main app.

Project structure:

  1. getIt_issue main project.
  2. lib_common library in getIt_issue folder that has components used in the main project.

Note: Issue is only present on web in release or profile mode.

  1. To generate getIt files - "flutter packages pub run build_runner build --delete-conflicting-outputs" in the root getIt_issue folder;
  2. Then to run the app on web in profile mode - "flutter run --profile -d chrome --dart-define=Dart2jsOptimization=O0"

When opening the console, the following error is shown:

image

Otherwise, in debug mode, works properly and displays a button that calls a method from injected service: image

P.S. The issue is not present also if the same classes are added to the main project (no lib_common present)

HKop avatar Feb 02 '22 21:02 HKop

This looks very much like a compiler bug

escamoteur avatar Feb 04 '22 09:02 escamoteur

OK, after looking a bit deeper into your provided project it really looks pretty odd what dart2js produces here

_i1.GetIt $initGetIt(_i1.GetIt get,
    {String? environment, _i2.EnvironmentFilter? environmentFilter}) {
  final gh = _i2.GetItHelper(get, environment, environmentFilter);
  final libCommonModule = _$LibCommonModule(get);
  gh.factory<_i3.ISecureStorage>(() => libCommonModule.webSecureStorage,
      registerFor: {_web});
  gh.factory<_i3.ISecureStorage>(() => libCommonModule.mobileSecureStorage,
      registerFor: {_mobileOrDesktop});
  gh.lazySingleton<_i3.AppSecureStorage>(
      () => libCommonModule.appSecureStorage);
  gh.singleton<_i4.ObjectManager>(libCommonModule.objectManager);
  return get;
}

this is the dart code where it happens

the JS code for this part looks like

    $initGetIt(get, environment) {
      var t3, _null = null,
        gh = A.GetItHelper$(get, environment, _null),
        libCommonModule = new A._$LibCommonModule(get),
        t1 = type$.String,
        t2 = type$.ISecureStorage;
      gh.factory$1$2$registerFor(new A.$initGetIt_closure(libCommonModule), A.LinkedHashSet_LinkedHashSet$_literal(["web"], t1), t2);
      gh.factory$1$2$registerFor(new A.$initGetIt_closure0(libCommonModule), A.LinkedHashSet_LinkedHashSet$_literal(["mobileOrDesktop"], t1), t2);
      if (gh._canRegister$1(_null))
        gh.getIt.registerLazySingleton$1$3$dispose$instanceName(new A.$initGetIt_closure1(libCommonModule), _null, _null, type$.AppSecureStorage);
      t1 = get.call$0();
      if (gh._canRegister$1(_null)) {
        t2 = A._setArrayType([], type$.JSArray_ObjectManager);
        t3 = type$.void;
        gh.getIt._register$3$6$disposeFunc$instance$instanceName$isAsync$shouldSignalReady$type(_null, new A.ObjectManager(t1), _null, false, type$.List_WillSignalReady._is(t2), B._ServiceFactoryType_1, type$.ObjectManager, t3, t3);
      }
      return get;
    },

I have no idea were this line comes from

  t1 = get.call$0();

also, the variable t1 isn't used anymore inside this function.

Looking at the code of call$0 it gets even weirder

    call$1$0($T) {
      var instance, _null = null,
        instanceFactory = this._findFirstFactoryByNameAndTypeOrNull$1$2$type(_null, _null, $T),
        t1 = instanceFactory.pendingResult;
      if (t1 != null) {
        t1 = instanceFactory.instance;
        t1.toString;
        instance = t1;
      } else
        instance = instanceFactory.getObject$2(0, _null, _null);
      return $T._as(instance);
    },
    call$0() {
      return this.call$1$0(type$.Object);
    },

and I have no idea which part of my get_it package this should come from? My only hunch is could that be created from an assert because the toString() is really weird especially as the result isn't assigned to anything.

@kevmoo @leafpetersen

Several of my users are affected by this.

escamoteur avatar Feb 04 '22 10:02 escamoteur

Flagging our web team on this now!

kevmoo avatar Feb 04 '22 15:02 kevmoo

Thanks a lot

escamoteur avatar Feb 04 '22 15:02 escamoteur

I'll follow up in more detail in the dart-sdk bug, but wanted to mention a couple things I noticed in my investigation:

  • the .pendingResult or .toString are signal of a null-check failing
  • the t1 = call$0() comes from inlining other code. In this case it is from the call method in the GetItImplementation class. Which is invoked from this piece of generated code:
  _i4.ObjectManager get objectManager =>
      _i4.ObjectManager(_getIt<_i3.AppSecureStorage>());
  • it's quite likely that dart2js has a bug related to call methods. If I change the generated code by hand to use _getIt.get<i3.AppSecureStorage>(), then the code works for me locally.

Note that my experiments are with a trimmed-down version of the app, I haven't validated that this works again with the full application.

sigmundch avatar Feb 04 '22 21:02 sigmundch

Thanks a lot for verifying that there is indeed a problem in dart2js. It would be pretty strange that it's a get_it code problem when 1000s of people use it on all other platforms Am 4. Feb. 2022, 22:04 +0100 schrieb sigmundch @.***>:

I'll follow up in more detail in the dart-sdk bug, but wanted to mention a couple things I noticed in my investigation:

• the .pendingResult or .toString are signal of a null-check failing • the t1 = call$0() comes from inlining other code. In this case it is from the call method in the GetItImplementation class. Which is invoked from this piece of generated code:

_i4.ObjectManager get objectManager => _i4.ObjectManager(_getIt<_i3.AppSecureStorage>());

• it's quite likely that dart2js has a bug related to call methods. If I change the generated code by hand to use _getIt.get<i3.AppSecureStorage>(), then the code works for me locally.

Note that my experiments are with a trimmed-down version of the app, I haven't validated that this works again with the full application. — Reply to this email directly, view it on GitHub, or unsubscribe. Triage notifications on the go with GitHub Mobile for iOS or Android. You are receiving this because you were mentioned.Message ID: @.***>

escamoteur avatar Feb 04 '22 21:02 escamoteur

Any news on this? atm I can't compile my project to web. Maybe a temp fix?

Same error
Uncaught TypeError: Cannot read properties of null (reading 'toString')
  at html_dart2js.dart:40810:45
  at a6c.a (async_patch.dart:316:19)
  at a6c.$2 (async_patch.dart:341:23)
  at Object.ab (async_patch.dart:246:3)
  at a6N (main.dart:10:27)
  at js_helper.dart:2684:31
  at js_helper.dart:2684:31
  at dartProgram (js_helper.dart:2684:31)
  at js_helper.dart:2684:31

JHBitencourt avatar Feb 17 '22 16:02 JHBitencourt

Regarding the original issue here, note that we've continued the dart level discussion at https://github.com/dart-lang/sdk/issues/48304 - the specific issue with the get_it package relates to using callable objects via the call method.

@JHBitencourt - your error could potentially be caused by something else. toString is the way dart2js represents null checks when emitting JavaScript, so this could be any kind of null check in a program. Usually those can be detected when running the application in debug mode. If not, I'd recommend trying first to isolate the issue in profile mode (where dart2js generates almost identical code to release mode but disables name minification).

sigmundch avatar Feb 17 '22 17:02 sigmundch

@sigmundch thanks for replying. When in debug everything works perfect. Both profile and release mode produce the same output. I came here because at a6N (main.dart:10:27) points to where I'm making a get_it call. I'll investigate further though.

JHBitencourt avatar Feb 17 '22 17:02 JHBitencourt

Any news on this? atm I can't compile my project to web. Maybe a temp fix?

Same error

Here (https://github.com/HKop/getit-issue) on another branch (called no-injectable) I managed to make it work, but it's not an ideal solution - in my case I tried registering dependencies manually in the lib_common package (without @injectable annotations). I still used @injectable in the main app with no problems. This resolved the issue for me, though I'd much prefer to use annotations with getIt instead of registering them manually.

HKop avatar Feb 18 '22 11:02 HKop

There ara a related problem with flutter web, if you use getIt.registerSingleton<AppModel>(AppModelImplementation()); the error is NoSuchMethodError: method not found: 'pendingResult' on null but if use getIt.registerLazySingleton<RESTAPI>(() => RestAPIImplementation()); the error is NoSuchMethodError: method not found: 'db' on null

Spiderbezno avatar Mar 22 '22 13:03 Spiderbezno

As a temporary solution i solved it by removing arguments from constructors of injected classes and I assigned every field with getIt().value

kosiarska avatar Mar 22 '22 13:03 kosiarska

does this problem still exist? because a fix was added into the dart2js if I read the above link correctly?

escamoteur avatar Apr 15 '22 09:04 escamoteur

To clarify - the fix landed in the Dart sdk and is part of the Dart 2.17 beta at the moment, it should be part of the 2.17 stable once that gets released. If flutter beta is in sync with Dart beta releases (which I believe it is), then I'd expect this to be resolved in both the master and beta flutter channels at the moment, but not on the stable channel.

sigmundch avatar Apr 19 '22 23:04 sigmundch

can anyone confirm, that this is now solved?

escamoteur avatar May 08 '23 10:05 escamoteur