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

Catch a Thrown Exception from Another Function #22734

Closed
pahlevi91 opened this issue Oct 5, 2018 · 14 comments
Closed

Catch a Thrown Exception from Another Function #22734

pahlevi91 opened this issue Oct 5, 2018 · 14 comments

Comments

@pahlevi91
Copy link

pahlevi91 commented Oct 5, 2018

Hi,
I am new to Flutter, I have a problem when I am trying to catch a thrown exception from another function. Here is the source code that I got from here.

The function A that throws an Exception

Future<User> login(String username, String password) {    
    return _netUtil.post(LOGIN_URL, body: {
      "username": username,
      "password": password
    }).then((dynamic res) {
      if(res["user"].containsKey["errors"]) {
        throw new Exception("There is an error!");
      } 
      return new User.map(res["user"]);
    });
  }

The function B that catches an exception then show it to the user

class LoginScreenPresenter {
  LoginScreenContract _view;
  RestDatasource api = new RestDatasource();
  LoginScreenPresenter(this._view);

  doLogin(String username, String password) {
    api.login(username, password).then((User user) {
      _view.onLoginSuccess(user);
    }).catchError((Exception error) {
      _view.onLoginError(error.toString());
    });
  }
}

However, there is a runtime error in function A:

E/flutter ( 8063): [ERROR:flutter/shell/common/shell.cc(182)] Dart Error: Unhandled exception:
E/flutter ( 8063): 'dart:async/future_impl.dart': Failed assertion: line 146: '<optimized out>': is not true.
E/flutter ( 8063): #0      _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39)
E/flutter ( 8063): #1      _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5)
E/flutter ( 8063): #2      _FutureListener.handleError (dart:async/future_impl.dart:146:14)
E/flutter ( 8063): #3      Future._propagateToListeners.handleError (dart:async/future_impl.dart:654:47)
E/flutter ( 8063): #4      Future._propagateToListeners (dart:async/future_impl.dart:675:24)
E/flutter ( 8063): #5      Future._completeError (dart:async/future_impl.dart:494:5)
E/flutter ( 8063): #6      _SyncCompleter._completeError (dart:async/future_impl.dart:55:12)
E/flutter ( 8063): #7      _Completer.completeError (dart:async/future_impl.dart:27:5)
E/flutter ( 8063): #8      _RootZone.runBinary (dart:async/zone.dart:1384:54)
E/flutter ( 8063): #9      _FutureListener.handleError (dart:async/future_impl.dart:143:20)
E/flutter ( 8063): #10     Future._propagateToListeners.handleError (dart:async/future_impl.dart:654:47)
E/flutter ( 8063): #11     Future._propagateToListeners (dart:async/future_impl.dart:675:24)
E/flutter ( 8063): #12     Future._complete (dart:async/future_impl.dart:476:7)
E/flutter ( 8063): #13     _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
E/flutter ( 8063): #14     _AsyncAwaitCompleter.complete (dart:async/runtime/libasync_patch.dart:28:18)
E/flutter ( 8063): #15     _completeOnAsyncReturn (dart:async/runtime/libasync_patch.dart:295:13)
E/flutter ( 8063): #16     _withClient (package:http/http.dart)
E/flutter ( 8063): <asynchronous suspension>
E/flutter ( 8063): #17     post (package:http/http.dart:69:5)
E/flutter ( 8063): #18     NetworkUtil.post (package:cownect_mobile/utils/network_util.dart:26:12)
E/flutter ( 8063): #19     RestDatasource.login (package:cownect_mobile/data/rest_data_format.dart:12:21)
E/flutter ( 8063): <asynchronous suspension>
E/flutter ( 8063): #20     LoginScreenPresenter.doLogin (package:cownect_mobile/screens/login/login_screen_presenter.dart:15:9)
E/flutter ( 8063): #21     _LoginScreenState._submit (package:cownect_mobile/screens/login/login_screen.dart:55:18)
E/flutter ( 8063): #22     _LoginScreenState.build.<anonymous closure> (package:cownect_mobile/screens/login/login_screen.dart:171:29)
E/flutter ( 8063): #23     _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
E/flutter ( 8063): #24     _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
E/flutter ( 8063): #25     GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
E/flutter ( 8063): #26     TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
E/flutter ( 8063): #27     TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:204:7)
E/flutter ( 8063): #28     GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
E/flutter ( 8063): #29     _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:147:20)
E/flutter ( 8063): #30     _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
E/flutter ( 8063): #31     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
E/flutter ( 8063): #32     _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
E/flutter ( 8063): #33     _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
E/flutter ( 8063): #34     _invoke1 (dart:ui/hooks.dart:153:13)
E/flutter ( 8063): #35     _dispatchPointerDataPacket (dart:ui/hooks.dart:107:5)

I'm stuck in this error and already looked for the solution but still no result.

@zoechi
Copy link
Contributor

zoechi commented Oct 5, 2018

It's easier to use async/await with try/catch than the catchError API where it is easier to use it wrongly

class LoginScreenPresenter {
  LoginScreenContract _view;
  RestDatasource api = new RestDatasource();
  LoginScreenPresenter(this._view);

  doLogin(String username, String password) {
    try {
      var user = await api.login(username, password);
      _view.onLoginSuccess(user);
    } on Exception catch(error) {
      _view.onLoginError(error.toString());
    }
  }
}

Please consider asking support questions in one of the other channels listed at http://flutter.io/support .

@zoechi zoechi added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Oct 5, 2018
@pahlevi91
Copy link
Author

pahlevi91 commented Oct 5, 2018

The _view.onLoginSuccess(user); function expects user variable with User type not Future < User > type, how to handle it?

*edited

@no-response no-response bot removed the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Oct 5, 2018
@pahlevi91
Copy link
Author

pahlevi91 commented Oct 5, 2018

I just added 'async' in the function declaration, and it works! Thanks!

  doLogin(String username, String password) async {
    try {
     var user = await api.login(username, password);
      _view.onLoginSuccess(user);
    } on Exception catch(error) {
      _view.onLoginError(error.toString());
    }
  }

@swordensen
Copy link

Does the .catchError method simply not work?

@zoechi
Copy link
Contributor

zoechi commented Jan 21, 2019

@Mikkal24 sure it does, but it's a bit tricky to get it right for all cases.
async/await with try/catch is much harder to get wrong.

@swordensen
Copy link

I think I got it to work but, my debugger is still dealing with the exception as if it was un-handled. Separate issue I think.

@zoechi
Copy link
Contributor

zoechi commented Jan 21, 2019

@Mikkal24 please report in https://github.com/dart-lang/sdk/issues

@sjmcdowall
Copy link
Contributor

@zoechi -- The issue I have with your suggestion is that there are many cases where await can't be used in Flutter... For example, in form validation (validators) .. where you have to be "sneaky" and use things like .then() within a sync function for it to be happy and not have the linter complain right and left (using the Google linting rules) ..

Since I am getting the same error -- I am wondering if there is a more concrete explanation of what the error means (it's certainly opaque at best) ...

@zoechi
Copy link
Contributor

zoechi commented Jan 28, 2019

@sjmcdowall if you mean '<optimized out>' then this is a compiler problem which removes source information required to print a proper error message. I think this was fixed already upstream and perhaps even in Flutter dev or master channel.
If you mean something else, please elaborate.

You can call async functions from everywhere. There are some places where Flutter does not wait for async results because it doesn't make sense because it needs to provide a result for the next screen render (initState(), build(), ...).

I would need more details to give concrete advice,
but in validation you'd need to return an intermediate result (valid or invalid) without really knowing and when the async result arrives have the view updated with the validation result that uses the result from the previous async response to calculate the real validation result.

@sjmcdowall
Copy link
Contributor

sjmcdowall commented Jan 28, 2019

@zoechi -- Hey Günter! I guess what I was saying -- for a concrete example-- is I have a validator function in a form field. If I try to use an async function

Future<String> _myValidator(String value) async {} 

Then the linter complains (or compiler?) that the return type of Future<String> isn't compatible with the function type String. You get the idea -- so obviously I can't use an async function anywhere per se -- at least not directly. So hence my statement one needs to "get tricky" about using them mixed with sync functions -- which is exactly what you indicate in your last paragraph -- and yes, that is exactly the right type of solution of course -- one though that many people need to "learn" how to do in Flutter since it's not as straightforward ..

I would think this is a good idea as part of the "Cookbook" .. how to integrate async functions through out the Flutter landscape in various "common" places... I don't think that has been done has it? I.e. best practices for each type -- build() { Futurebuilder, Streambuilder } -- validation -- etc?

Anyway, the original error optimized out I had was because in my .catchError I had a type of "Error error" -- but I guess the proper type is just "Object error"? which seems rather "odd" in a strongly typed language like Dart could be? Is there a "proper" type error type (that doesn't sound like English! LOL) that one should use in a .catchError() if one is using that or is Object really the proper type? It doesn't have much in the way of helpful methods though.. ??

Cheers!!

@zoechi
Copy link
Contributor

zoechi commented Jan 28, 2019

@sjmcdowall
The pattern is quite the same. Call the async function and call setState(...) when the async result becomes available and then when build() is called again because of setState(...), use the async result.

Then the linter complains

I'd consider that a good thing because it tells you that what you are attempting works agains the framework.

build() { Futurebuilder, Streambuilder }

I think this one is covered pretty well.

validation

For async validator you can thumbs-up and follow #9688

If there are others check if there exists an issue already or create one.

I can't really make sense of your last paragraph.
That would require a minimal reproduction and the full error output you get, but probably better to ask on StackOverflow and create a new issue if it turns out there is actually something to for the Flutter team (fix a bug, add a feature, improve docs).

@FabioPagano
Copy link

FabioPagano commented Aug 31, 2019

It's easier to use async/await with try/catch than the catchError

I had the same problem of the original poster, but in my case I missed an "await" calling the function "A" from the function "B" (thank you for the hint given by the answer) so the catch in the function "B" (that I wanted to show) was evaluated before the catch of the function "A" (because in that moment there were no error yet raised by the function "A", therefore the catch in the function "B" was not invoked). Adding the missing "await" (it was my failure) calling the "A" function, the catch of the function "B" catched the error raised by the function "A" as expected and the catch of the function "B" showed the error thrown by function "A".

@olaide-ekolere
Copy link

.catchError((error) {
print('$error');
errorMessage = '$error';
}
but there is always an 'Exception:' prefix

@github-actions
Copy link

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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 28, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants