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 try catch can't catch SocketException ( Exception has occurred. SocketException (SocketException: OS Error: No route to host, errno = 113) #551

Open
sujith2014 opened this issue Mar 23, 2021 · 33 comments

Comments

@sujith2014
Copy link

Flutter App crashed after getting this exception

Exception has occurred.
SocketException (SocketException: OS Error: No route to host, errno = 113, address = 10.162.18.32, port = 60208)

THE same URL is accessible from the testing phone, Postman.
also tried with

try {

} on SocketException {

}

Still, Exception is not handled.

 
 Future<List<Post>> getPosts() async {
    final prefs = await SharedPreferences.getInstance();
    final key = 'token';
    print(prefs.get(key));
    final value = prefs.get(key) ?? 0;
    Map<String, String> headers = {
      "Accept": "application/json",
      "Authorization": "Bearer $value"
    };
    print("before res");
    var responseJson;
    try {
      print("ins try get url " + host + "posts");
      final response = await http.get(host + "posts",
          headers: headers);   //Exception on this line
      print("final try");
      responseJson = _response(response);
    } catch (e) {
      print(e);
      return null;
      //throw FetchDataException('No Internet connection');
    }
    // if (res.statusCode == 200) {
    List<dynamic> body = responseJson;

    List<Post> posts = body
        .map(
          (dynamic item) => Post.fromJson(item),
        )
        .toList();

    return posts;
    // } else {
    //   print('A network error occurred');
    //   //throw "Can't get posts.";
    // }
  }

flutter doctor

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.0.2, on Microsoft Windows [Version 10.0.18363.836], locale en-US)
[√] Android toolchain - develop for Android devices (Android SDK version 30.0.1)
[√] Chrome - develop for the web
[√] Android Studio (version 4.1.0)
[√] VS Code (version 1.54.3)
[√] Connected device (2 available)

• No issues found!
PS C:\Users\nicalp\AndroidStudioProjects\vikasapp> flutter --version
Flutter 2.0.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 8962f6dc68 (11 days ago) • 2021-03-11 13:22:20 -0800
Engine • revision 5d8bf811b3

Screenshots

https://i.ibb.co/VVHV3Sr/image.png

https://i.ibb.co/GMRZZ21/image.png

@EgHubs
Copy link

EgHubs commented Mar 29, 2021

same here:
flutter: SocketException: Connection failed (OS Error: Network is unreachable, errno = 51), address = 192.168.4.1, port = 80
though it's accessible from my phone's google chrome.

[✓] Flutter (Channel master, 2.1.0-13.0.pre.294, on macOS 11.2.3 20D91 darwin-x64, locale en)
    • Flutter version 2.1.0-13.0.pre.294 at /Users/shalaby/Developer/flutter
    • Framework revision a603714610 (25 hours ago), 2021-03-28 03:54:02 -0700
    • Engine revision b5e15d055d
    • Dart version 2.13.0 (build 2.13.0-162.0.dev)

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Users/shalaby/Library/Android/sdk
    • Platform android-30, build-tools 30.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.4, Build version 12D4e
    • CocoaPods version 1.10.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] VS Code (version 1.54.3)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.20.0

[✓] Connected device (2 available)
    • Mahmoud’s iPhone (mobile) • 00008030-00037981012A802E • ios            • iOS 14.4.2
    • Chrome (web)              • chrome                    • web-javascript • Google Chrome 89.0.4389.90

• No issues found!

tested on stable, dev, and master channels.
using latest package release

@bhtri
Copy link

bhtri commented Mar 30, 2021

I also had a similar problem in case the server still hasn't started.
App crash right at this line of code

例外が発生しました
SocketException (SocketException: OS Error: Connection refused, errno = 111, address = 192.168.xxx.xxx, port = xxx)
flutter doctor 
[✓] Flutter (Channel stable, 2.0.3, on macOS 11.2.3 20D91 darwin-x64, locale ja-JP)
    • Flutter version 2.0.3 at $HOME/develop/flutter
    • Framework revision 4d7946a68d (11 days ago), 2021-03-18 17:24:33 -0700
    • Engine revision 3459eb2436
    • Dart version 2.12.2

pubspec.yaml
  http: ^0.13.1

If it could catch the exception and proceed logically instead of crashing the app then maybe better.

@EgHubs
Copy link

EgHubs commented Mar 30, 2021

If it could catch the exception and proceed logically instead of crashing the app then maybe better.

so is there is a workaround?

@bhtri
Copy link

bhtri commented Mar 31, 2021

@EgHubs how did it workaround??

@EgHubs
Copy link

EgHubs commented Mar 31, 2021

@EgHubs how did it workaround??

Iam asking if you solved it.

@bhtri
Copy link

bhtri commented Mar 31, 2021

I still haven't solved it yet 😅

@Vakil-Parth
Copy link

+1

@flo80
Copy link

flo80 commented Apr 12, 2021

I got a similar issue when using http.post and my test server is not running.

At least for my issue, it seems like IOClient is only catching HttpExceptions but somewhere in HttpClient.openUrl a SocketException can be thrown.

But I use some async code to catch the error and don't have issues with this; maybe worth trying for others with issues

return http
    .post(
  cloudUri,
  headers: { 'Content-Type': 'application/json'  },
  body: jsonString,
)
    .then((response) {
  if (response.statusCode == 200) {
    _log.fine('event sent');
    return Future.value();
  } else {
    _log.info('event could not be sent, status ${response.statusCode}');

    return Future.error(
        'http error code ${response.statusCode.toString()}');
  }
}).onError((error, stackTrace) {
  _log.warning('could not send event, error ', error);
  
  // catch error here
  return Future.value();
});

@0xNF
Copy link

0xNF commented May 19, 2021

I also encountered this with a socket exception. Quite frustrating.
SocketException: OS Error: Connection timed out, errno = 110, address = 192.168.0.1, port = 37694

edit:

I should clarify that I'm not just getting a random socket exception -- the method I'm calling that contains my http.get method is throwing a socket exception and then exiting the method without falling to any catch blocks.

Like flo80 said, this happens when the server in question is offline, meaning no response is possible.

@kdeoliveira
Copy link

I have the same problem, but it seems to be a problem with flutter instead.

From the debugger it seems that exception is coming from the dart:io package

@natebosch
Copy link
Member

Can someone provide a complete minimal reproduction case and instructions to see this behavior?

I have not been able to locally reproduce a case where using try, await, and catch doesn't catch the exception. When I run in an ios simulator the SocketException gets caught by exactly the catch block I'd expect.

@david34corbalan
Copy link

i have the same error with subdomains in localhost ( http://sub.localhost:80/example ) . But i have not in ( http://localhost:80 ), help me please.

Flutter try catch can't catch SocketException ( Exception has occurred. SocketException (SocketException: OS Error: No route to host, errno = 8)

@natebosch
Copy link
Member

i have the same error

As above, we still need a reproduction case that we can debug.

@david34corbalan
Copy link

I solved the problem, when I use the package in localhost a vhost must be configured, that solved the problem. in my case use xampp with laravel in mac os.

example:
in the terminal write "vim /etc/hosts" to edit vhost

Captura de Pantalla 2021-08-26 a la(s) 22 11 52

127.0.0.1 subdomain.localhost

@joeloudjinz
Copy link

joeloudjinz commented Sep 24, 2021

This issue is hard to spot, at least in my case, i only know it is happening when i see the crashlytics dashboard.

Crashlytics report

Non-fatal Exception: FlutterError
SocketException: Connection failed (OS Error: No route to host, errno = 65), address = dundermifflin.com, port = 443. Error thrown null.
Non-fatal Exception: FlutterError
0  ???                            0x0 _HttpClient.openUrl (dart:_http)
1  ???                            0x0 IOClient.send + 30 (io_client.dart:30)
2  ???                            0x0 BaseClient._sendUnstreamed + 93 (base_client.dart:93)
3  ???                            0x0 BaseClient.post + 32 (base_client.dart:32)
4  ???                            0x0 RestServiceBase.postData + 63 (rest_service_base.dart:63)
5  ???                            0x0 UserRestService.getNewNotifications + 206 (user_rest_service.dart:206)
6  ???                            0x0 LandingScreenStateProvider._pollNotifications + 298 (landing_state_provider.dart:298)

My code

@protected
  Future<Map<String, dynamic>> getData(Uri url) async {
    http.Response result;
    final httpClientInstance = new httpClient.IOClient();
    try {
      result = await httpClientInstance.get(url, headers: this._getHeaders());
    } catch (ex, s) {
      // process error
    } finally {
      httpClientInstance.close();
    }

    if (await _processResponseForTokenRefreshment(result)) {
      return getData(url);
    }

    return this._processResponse(result);
  }

@Marcel2508
Copy link

Marcel2508 commented Oct 8, 2021

I came across the same issue today. It seems to be an error thrown inside the http package itself outside of the async/await context, so it cannot be handled by try-catch..

Looks like the issue is thrown in io_client.dart line 30:

var ioRequest = (await _inner!.openUrl(request.method, request.url))

Any progress on this?

Code to reproduce: #508 (comment)

@alexaniko88
Copy link

Any progress here?

@david-kooi
Copy link

Also having this issue. This bug is cluttering log outputs.

@ColbyClarke
Copy link

I had the same issue, I'm not sure if my catch was only catching http errors but when I changed my
try{} catch(e){}

to

try{
} on Exception catch (e) {
}

it seems to work

@laurensdewaele
Copy link

laurensdewaele commented May 12, 2022

See this issue

We need to use the onError callback as well.

try {
   socket = socket.connect().onError((e){
    throw e as SocketException;
  })
} catch (e) {
   // Now it will finally get in the handler
}

Also, I programatically close the socket

await _socket?.close().onError((error, stackTrace) => null);

If I omit the onError, I get uncaught SocketExceptions.
The weird thing is that I tried to add some logic in the onError (except returning null) and the app would crash.
The annoying thing is that I can't properly debug, since it only happens on physical iOS devices when the app has been suspended by the OS.

Soo.... No clue what's going on here

@AliAkberAakash
Copy link

Calling the error throwing function inside runZonedGuarded helped me catch the error.

@michpolicht
Copy link

Now good luck with WebSocketChannel.connect(), which isn't async and seems to wrap HTTPClient...

@matcaste
Copy link

matcaste commented Apr 5, 2023

In my case, removing the timeout duration specification seems to have fixed the error.

I changed somthing like this:

import 'package:http/http.dart' as http;

// ...

response = await http.post(
          Uri.http(theUri),
          headers: theHeaders,
          body: theBody,
        ).timeout(Duration(seconds: theTimeout));

into somenthing like this:

import 'package:http/http.dart' as http;

// ...

response = await http.post(
          Uri.http(theUri),
          headers: theHeaders,
          body: theBody,
        );

@Sajonji
Copy link

Sajonji commented Jun 12, 2023

I'm also experiencing this issue.
And like @matcaste using a timeout on the http Future (get-Requests in my case) is the issue.

I'm sending multiple get requests, and it seems to me that with a timeout shorter than this packages internal timout you will run into this issue. Probably because the code execution has moved on already and the catch statement is no longer actively looking for something to catch.

EDIT: to clarify, this is indeed not a bug in http package, but a bug in Dart and Futures. Or my and others limited knowledge of Futures and not knowing how to correctly handle this behaviour. Here is a minimal reproducable example:

Future<void> main() async {
  try {
    var resultFuture = complexAsyncTask();
    var timeoutFuture = resultFuture.timeout(const Duration(seconds: 1), onTimeout: () {
      print("timeout");
      return "timeout return";
    });

    final String result = await timeoutFuture;

    print(result);
  } catch (e) {
    print("catched exception: $e");
  }
}

Future<String> complexAsyncTask() => _withTryFinallyAwait(() => _complexAsyncTask());

Future<T> _withTryFinallyAwait<T>(Future<T> Function() fn) async {
  try {
    return await fn();
  } finally {
    print("finally");
  }
}

Future<String> _complexAsyncTask() async {
  return await Future.delayed(const Duration(seconds: 2), () {
    throw Exception('exception thrown after 2 seconds delay');
    //return "success";
  });
}

If we await resultFuture (like in the example code), we have to wait for 2 seconds and the exception will be catched correctly.
However, if we instead await the timeoutFuture (switch the comment to await resultFuture) we only wait for 1 second until the timeout happens and thrown Exception does NOT get catched.

Anybody knows how to wait only for the timeout but still catch an exception thrown in the async task ?

@Leobuaa
Copy link

Leobuaa commented Aug 9, 2023

Any update here?

@MalouLandsgaard
Copy link

+1

@bkan36
Copy link

bkan36 commented Sep 26, 2023

Hi, I got the same error and I fixed it by using

runZonedGuarded

here's my code

Future<Response?> post(String path, dynamic parameter) async =>
      runZonedGuarded<Future<Response?>>(() async {
        return await client.post(path,
            data: json.encode(parameter),
            options: Options(
              headers: headers
                ..addAll(<String, String>{
                  'Authorization': await localData.read(accessTokenName) ?? ''
                }),
            ));
      }, (error, stack) {
        throw Exception('SERVER DOWN');
      });

https://api.flutter.dev/flutter/dart-async/runZonedGuarded.html

for more explanation
https://www.youtube.com/watch?v=pHpvfaanrbw&list=PLJbE2Yu2zumC4_aB75G2lQ-tAZlqIOGVx&index=3

@CrownedComedian
Copy link

BLESS YOU!!! @bkan36

@bkan36
Copy link

bkan36 commented Sep 30, 2023

thanks @CrownedComedian.
Do you have any mistakes when your server return a fail response like 400, 403... etc ??
After I've solved the socket exception uncaught I was trouble shooting another issue when my back-end return a failed response, So I tried to solve the problem, but unfortunately I wasn't successful, then I back to the version that worked and this code no longer works -___- (this weird issue has tired me);

At the moment I gave up and will continue to develop other features....

@CrownedComedian
Copy link

My situation is a bit different then that mentioned in this thread -- I was lucky to have even stumbled upon it. I've been working on an app to run provisioning code for my ESP device. Using Flutter's http package to communicate to the device abruptly ended my connection for some unknown reason, so I'm using platform specific code which seems to handle things. The exception I was getting was:
java.net.SocketException: socket failed: ENONET (Machine is not on the network)
And the basic gist of my Flutter/Dart code now includes:

Future<void> _runInZonedGuard() async {
  try {
    await _platform.invokeMethod(methodName, input).then((results) => {
      // cry happy tears
    }).onError((error, stack) => {
        // platform code called .error()
    });
  } catch (e) {
    // platform code threw exception
  }
}
runZonedGuarded(() => _runInZonedGuard(), (error, stack) {
  // I haven't gotten this to execute but it still works just fine
});

Then my platform code has the normal .setMethodCallHandler() with a switch statement in it that will run a call to my ESP device on a background thread via a Handler with a listener that will return .success() or .error() as usual. The SocketException was not being caught (even though other exceptions were) until I added your suggested code. Not sure if that answers your question, but maybe something you can try. Hope it helps! @bkan36

@MathewsRony
Copy link

I'm trying to build an iOS app with Flutter, but I keep getting this error: Unhandled Exception: ClientException with SocketException: Connection failed (OS Error: No route to host, errno = 65), address = t*********.com, port = 443. Does anyone know how to fix this? I'm using the latest version of Flutter and Xcode. Thanks in advance.

@christophmerscher
Copy link

christophmerscher commented Feb 17, 2024

Is their a solution for this issue? Or some way to avoid that the app freeze and stops working?

If I turn Off(on purpose) my server and try a simple get request with a Timeout Duration (AS mentioned by @Sajonji ) the Clientexception will be thrown and the app will stop to Work.

An easy to reproduce case:

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() async {
  runApp(
    const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: BaseLayout(),
    );
  }
}

class BaseLayout extends StatefulWidget {
  const BaseLayout({Key? key}) : super(key: key);

  @override
  _BaseLayoutState createState() => _BaseLayoutState();
}

class _BaseLayoutState extends State<BaseLayout> {
  Uri nonExisitingUrl = Uri.https("SOMEIP:SOMEPORT); // Here I put the ip address of my pc running the AVD and some non reachable port
  int value = 0;

  Future<void> errorShowCase(bool showTheUncatchableError) async {
    try {
      print("Start Call");
      if (showTheUncatchableError) {
        print("Wait for 1 second");
        final response =
            await http.get(nonExisitingUrl).timeout(const Duration(seconds: 1));
      } else {
        print("Wait flutter default time");
        final response = await http.get(nonExisitingUrl);
      }
    } catch (e, stackTrace) {
      print("Error $e");
      print("StackTrace $stackTrace");
    }
    print("End Call");
    setState(() {
      value += 1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onTap: () async {
          await errorShowCase(true);
        },
        child: Container(
          padding: const EdgeInsets.all(16),
          child: Text('Value: $value'), // Show value
        ));
  }
}

When running the snippet with wait errorShowCase(true); the Log output looks as follow:

Connecting to VM Service at ws://127.0.0.1:55151/94XRqVvunxY=/ws
I/flutter (11814): Start Call
I/flutter (11814): Wait for 1 second
I/flutter (11814): Error TimeoutException after 0:00:01.000000: Future not completed
I/flutter (11814): StackTrace 
I/flutter (11814): End Call
D/EGL_emulation(11814): app_time_stats: avg=5127.44ms min=19.18ms max=15265.15ms count=3

However if now you let the App run without doing anything you will get the error (Note it can take up to 5 Minutes until this happens):

Ausnahme aufgetreten.
_ClientSocketException (ClientException with SocketException: Connection timed out (OS Error: Connection timed out, errno = 110), address = https://SOMEIP, port = SOMEPORT, uri=https://SOMEIP:SOMEPORT)

From the package io_client.dart (line 119):

    } on SocketException catch (error) {
      throw _ClientSocketException(error, request.url);

If however you call the method like this await errorShowCase(false); the output will be

Connecting to VM Service at ws://127.0.0.1:55436/hpdr2A97fnU=/ws
I/flutter (11938): Start Call
I/flutter (11938): Wait flutter default time

Again we need to wait almost 5 Minutes:

I/flutter (11938): Error ClientException with SocketException: Connection timed out (OS Error: Connection timed out, errno = 110), address = SOMEIP, port = SOMEPORT, uri=https://SOMEIP:SOMEPOR
I/flutter (11938): StackTrace #0      IOClient.send (package:http/src/io_client.dart:119:7)
I/flutter (11938): <asynchronous suspension>
I/flutter (11938): #1      BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:32)
I/flutter (11938): <asynchronous suspension>
I/flutter (11938): #2      _withClient (package:http/http.dart:166:12)
I/flutter (11938): <asynchronous suspension>
I/flutter (11938): #3      _BaseLayoutState.errorShowCase (package:aps/main.dart:45:26)
I/flutter (11938): <asynchronous suspension>
I/flutter (11938): #4      _BaseLayoutState.build.<anonymous closure> (package:aps/main.dart:61:11)
I/flutter (11938): <asynchronous suspension>
I/flutter (11938): End Call
D/EGL_emulation(11938): app_time_stats: avg=48491.19ms min=30.53ms max=145388.91ms count=3

However here the exception was caught and the app is still working. I tried all the fix attempts mentioned above (like using onError as mentioned by @flo80 ) however none of them is working. As @Sajonji mentioned the issue is only arising when we specify our own timeout. A workaround (probably one of the worst but a possibility) is to omit the timeout part in the http call.

@bsutton
Copy link

bsutton commented Mar 26, 2024

I'm having the same issue with the mailer package. If the connection port is incorrect then a uncatchable SocketException is thrown. So I suspect that the bug is not specifically an issue with the http package but rather the the Socket class in dart:io - for clarity I'm actually using the SecureSocket class but I suspect the problem is universal.

Here is the code in question:

import 'dart:io';

import 'package:logging/logging.dart';
import 'package:mailer/mailer.dart' as mailer show send;
import 'package:mailer/mailer.dart' hide send;
import 'package:mailer/smtp_server.dart';

import 'smtp_settings.dart';
import 'util/exceptions.dart';

class SmtpClient {
  factory SmtpClient() {
    if (_self == null) {
      throw StateError(
          '''You must initialise the SmtpClient. Call SmtpClient.fromArgs()''');
    }
    return _self!;
  }


  SmtpClient.fromArgs(
      {required this.host,
      required this.port,
      required this.useAuth,
      required this.useTLS,
      this.authUser,
      this.authPassword}) {
    smtpServer = SmtpServer(host,
        port: port,
        allowInsecure: !useTLS,
        username: authUser,
        password: authPassword);
  }
  static final logger = Logger('smtp');

  late final SmtpServer smtpServer;
  final String host;
  final int port;

  final bool useAuth;
  final bool useTLS;
  final String? authUser;
  final String? authPassword;

  static SmtpClient? _self;

  static const hostKey = 'smtp_host';
  static const portKey = 'smtp_port';

  /// Send an email
  /// Throws [SMTPException] if the send fails.
  Future<SendReport> send(
      {required EmailAddress from,
      required List<EmailAddress> to,
      required String subject,
      required String body,
      String? html,
      List<EmailAddress> cc = const [],
      List<EmailAddress> bcc = const []}) async {
    final message = Message()
      ..from = Address(from)
      ..recipients.addAll(to.map<Address>(Address.new))
      ..ccRecipients.addAll(cc.map<Address>(Address.new))
      ..bccRecipients.addAll(bcc.map<Address>(Address.new))
      ..subject = subject
      ..text = body;
    if (html != null) {
      message.html = html;
    }

    try {
      return mailer.send(message, smtpServer);
    
    } on SocketException catch (e) {
      /// fails to catch the Socket Exception
      throw SMTPException.withCause(e.toString(), e);
    } on Exception catch (e) {
      throw SMTPException.withCause(e.toString(), e);
    }
  }
}

typedef EmailAddress = String;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests