Http: Cannot catch internal exceptions (e.g. SocketExceptions)

Created on 11 May 2018  ·  18Comments  ·  Source: dart-lang/http

Please consider the following snippet:

Future<http.Response> foo(url, headers) {
  try {
    return http.get(url, headers: headers);
  } catch (e) {
    print(e);
    return null;
  }
}

I have assumed that all internal exceptions will be handled internally and then will be rethrown to the calling layer (or at least will be thrown in a wrapping/abstracting exception).
Unfortunately, the catch block above isn't being called in case of such error (e.g. SocketException), instead, an Unhandled exception flow occurs:

E/flutter ( 6324): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 6324): SocketException: OS Error: Connection refused, errno = 111, address = 10.0.2.2, port = 49907
E/flutter ( 6324): #0      IOClient.send (package:http/src/io_client.dart:30:23)
E/flutter ( 6324): <asynchronous suspension>
E/flutter ( 6324): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:171:38)
E/flutter ( 6324): <asynchronous suspension>
E/flutter ( 6324): #2      BaseClient.get (package:http/src/base_client.dart:34:5)
E/flutter ( 6324): #3      get.<anonymous closure> (package:http/http.dart:47:34)
E/flutter ( 6324): #4      _withClient (package:http/http.dart:167:20)
E/flutter ( 6324): <asynchronous suspension>
E/flutter ( 6324): #5      get (package:http/http.dart:47:3)
...
...
...
Application finished.
Dart VM version: 2.0.0-dev.48.0.flutter-fe606f890b (Mon Apr 16 21:21:13 2018 +0000) on "macos_x64"
http: "^0.11.3+16"

How can I gracefully catch such exceptions?

question

Most helpful comment

The try/catch in your example is synchronous, whereas the exception is thrown asynchronously. If you mark your function async and await the future before you return it, you'll catch the exception as expected:

Future<http.Response> foo(url, headers) async {
  try {
    return await http.get(url, headers: headers);
  } catch (e) {
    print(e);
    return null;
  }
}

All 18 comments

The try/catch in your example is synchronous, whereas the exception is thrown asynchronously. If you mark your function async and await the future before you return it, you'll catch the exception as expected:

Future<http.Response> foo(url, headers) async {
  try {
    return await http.get(url, headers: headers);
  } catch (e) {
    print(e);
    return null;
  }
}

I see, thanks.

@nex3 I ran into this same problem but I was using async/await.

  final response = await http.get(url,
      headers: {
        "Accept": "application/json; charset=UTF-8",
        "Authorization" : "Bearer $jwt"
      },
  );

Dart Error: Unhandled exception: SocketException:

Seems like http just swallows the exception instead of bubbling it up.

@kmcgill88 - your code sample doesn't include the try/catch, does the exception get caught if you include one?

@natebosch, sorry I should have explained a little more than I did. I'm using this in Flutter with redux. I have something like

// foo_service.dart
Future<MyObject> loadMyObject(String url, String jwt) async {
final response = await http.get(url,
      headers: {
        "Accept": "application/json; charset=UTF-8",
        "Authorization" : "Bearer $jwt"
      },
  );
MyObject myObject = MyObject.fromJson(json.decode(response.body));
return myObject;
}

I call the service from a redux action.

// actions.dart
void someAction() async {
  try {
     MyObject myObj = await loadMyObject("blah.com", "abc123...");
  catch (exception) {
    // I get no exception here
    print(exception);
  }
}

I would except loadMyObject to fail and bubble up the exception from http.get. I will try wrapping the http.get directly and report back.

🤦‍♂️ It's working now. I honestly don't know what has changed. Thanks anyway.

how do you catch SocketException specifically.

// actions.dart
void someAction() async {
  try {
     MyObject myObj = await loadMyObject("blah.com", "abc123...");
  catch (exception) {
    // I get no exception here
    print(exception);
  }
}

This seems as it would catch any exception thrown. But I want to catch a specific exception - the SocketException. How do I go about that?

But I want to catch a specific exception

https://dart.dev/guides/language/language-tour#catch

@natebosch thanks, but there is no on SocketException. I can catch TimeoutException and some others but not on SocketException

I am using the package 'package:http/http.dart'

If you're running on the web where dart:io isn't available then I wouldn't expect a SocketException to be thrown. If you're running on the VM or flutter then you can import dart:io and catch SocketException. Some exceptions are thrown by the lower level libraries and not every exception that can be thrown is defined in this package...

gotcha.

I face the same problem,

Exception has occurred.
SocketException (SocketException: Failed host lookup: 'harianugrah.com' (OS Error: No address associated with hostname, errno = 7))

It made sense because my phone is not connected to internet. The problem is I can't catch the exception. Here is my code

  static Future<http.Response> postDataForCollection(
    http.Client client,
    String canvashpx,
    String canvaswpx,
    String userId,
    String stringEncodedOffset,
    AksaraModel aksara,
  ) async {
    try {
      var aksaraCode = aksara.code.toString();

      var res = await client
          .post('https://harianugrah.com/api/v1/collector', body: {
        "canvasHpx": canvashpx,
        "canvasWpx": canvaswpx,
        "idUser": userId,
        "points": stringEncodedOffset,
        "aksara": aksaraCode,
        "apiVer": '4',
      }).timeout(Duration(seconds: 20));

      if (res.statusCode != 201) {
        throw new MinorServiceException('Gagal mengirim data');
      }

      return res;
    } on SocketException catch (e) {
      throw new FatalServiceException('Gagal');
    } catch (e) {
      throw new FatalServiceException('Gagal');
    }
  }

@hariangr unfortunately with the http package - (can be used on both mobile and web apps), you can't directly call the on SocketException. However, with the dart.io platform (can only be used on non-web applications), you can explicitly call the on SocketException. If you still want to use he http package one work around is to do this:

try {
///
} on Exception catch(e) {
    if (e.toString().contains('SocketException')) {
        throw new FatalServiceException('Gagal'):
    }
   //do something else
} 

@hariangr

The problem is I can't catch the exception.

We've still been unable to have anyone demonstrate a reproduction case for this - Do you have the import to dart:io and the on clause and the exception is still not getting caught? Is this reproducible?

I realize this is closed, but @natebosch states he's been unable to find a reproducible case for this.
I've had the same problem, and put up a very simple app that demonstrates the issue.

Ideally the waiting indicator should be replaced by information on the error, but that's not the case.

https://github.com/alevinetx/flutter_async_http_control

@alevinetx - You have an uncaught async error. From what I can tell the behavior you are seeing is expected for the way you wrote the code.

You return Future.error here: https://github.com/alevinetx/flutter_async_http_control/blob/5ed0dac6bb8572706d26d28b62fee5761d214b0b/lib/rest_code.dart#L76
This is in an async method. That behaves as if you had done a throw there.

There is no try around that call here: https://github.com/alevinetx/flutter_async_http_control/blob/5ed0dac6bb8572706d26d28b62fee5761d214b0b/lib/rest_code.dart#L21 so the exception bubbles up from there.

The call is made here, with no .then or .catchError, so it's an unhandled async error:
https://github.com/alevinetx/flutter_async_http_control/blob/5ed0dac6bb8572706d26d28b62fee5761d214b0b/lib/second_screen.dart#L29

I would expect for flutter to report this as you see.

See https://dart.dev/guides/libraries/futures-error-handling#potential-problem-accidentally-mixing-synchronous-and-asynchronous-errors

Was this page helpful?
0 / 5 - 0 ratings

Related issues

drishit96 picture drishit96  ·  3Comments

Blykam picture Blykam  ·  6Comments

Buckstabue picture Buckstabue  ·  7Comments

DartBot picture DartBot  ·  8Comments

plake876 picture plake876  ·  3Comments