http
http copied to clipboard
Unhandled exception that can never be handled
Info you may need
- Dart SDK version: 2.19.0 (stable) (Mon Jan 23 11:29:09 2023 -0800) on "windows_x64"
- Flutter 3.7.0 • channel stable • https://github.com/flutter/flutter.git Framework • revision b06b8b2710 (3 weeks ago) • 2023-01-23 16:55:55 -0800 Engine • revision b24591ed32 Tools • Dart 2.19.0 • DevTools 2.20.1
- http: ^0.13.5
The issue
I want to get data from two APIs so I call the two methods that return future and then await for their return value so that I don't wait if one takes too long. When I try to handle SocketException (no internet) from http.get() in the async function an unhandled exception still occurs breaking the program the exception is Exception has occurred. _ClientSocketException (Failed host lookup: 'APIs BASE_URL') from io_cleint.dart
, and this another traceback from the terminal
E/flutter (16549): #0 IOClient.send (package:http/src/io_client.dart:88:7)
E/flutter (16549): <asynchronous suspension>
E/flutter (16549): #1 BaseClient._sendUnstreamed (package:http/src/base_client.dart:93:32)
E/flutter (16549): <asynchronous suspension>
E/flutter (16549): #2 _withClient (package:http/http.dart:164:12)
E/flutter (16549): <asynchronous suspension>
How to reproduce it.
The code below was refactored to catch any thing because after hours and hours of debugging not figuring out why on SocketException wasn't working I tried to catch any exception and seeing it
home_page.dart
setState(() {
json = imageBytes = null;
});
Future<Uint8List> bytesImageFuture = getRandomImage();
Future<Map<String, dynamic>> decodedJsonFuture = getRandomFact();
try{
imageBytes = await bytesImageFuture;
json = await decodedJsonFuture;
} catch (e) {
print(e);
print(e.runtimeType);
socketException = true;
}
setState(() {});
}
images.dart
Uri url = Uri.https(BASE_URL, "cat");
http.Response response;
try {
response = await http.get(url);
} catch (_){
return UintList(0);
}
if (response.statusCode == 200) {
return response.bodyBytes;
}
throw Exception("Could not get random image ${response.statusCode}");
}
facts.dart
Uri url = Uri.https(BASE_URL, "facts/random");
Future<http.Response> responseFuture = http.get(url);
Future<List<String>> rejectedListFuture = loadPrefs(Mode.rejected.value);
List<String> rejectedList = await rejectedListFuture;
http.Response response;
try {
response = await responseFuture;
} catch (_){
return {};
}
if (response.statusCode == 200) {
Map<String, dynamic> decodedJson = jsonDecode(response.body);
if (rejectedList.every((element) => element != decodedJson['_id'])) {
return decodedJson;
} else {
return getRandomFact();
}
}
throw Exception("Could not get random fact ${response.statusCode}");
}
What I possibly found
I believe I might have figured out the problem. If you look at the traceback from the terminal it seems that the file http.dart in line 164 in the function _withClient<T> their is a try-finally block with no catch and for some reason, my code is not reciving any exceptions that come from this function the source of the error is this file alone it is not even showing which of the two functions I wrote is calling this method. This seems to be related to it being async and that my methods already return a value after handling any exceptions. I don't have a deep understanding of the http module or async in dart, so if my assumptions are wrong and I am the one that wrote this code in a wried way I hope you can help me in using this module the right way.
Future<T> _withClient<T>(Future<T> Function(Client) fn) async {
var client = Client();
try {
return await fn(client);
} finally {
client.close();
}
}
One more thing
I am not sure if this should be a separate issue or a question on StackOverflow I actually have already asked and this is the link to it, but as I said before the above could was changed a little bit. Previously my two methods to return data from the APIs would rethrow the SocketException so that if either of them had a problem but not the other I would know but this seems to also cause a problem like the try-catch block catch the on SocketException from one of them but not the other since it already caught I guess. Therefore is it wrong to rethrow the same error inside one try-catch. But even if I gave them separate try-catch an error still occurs. Honestly, I am tired, I tried a lot of things that I became confused by all the combinations I tried. I hope someone can help. Thanks in advance.
I'm having the same issue (both with http 0.13.6 and http 1.0.0) and I even tried a workaround that doesn't work : The following code
http.Response res;
try {
print('try');
res = await http.get(Uri.parse('<some url refused somehow>'));
print('success');
} catch (e) { // FIXME: 'failed to lookup host' isn't catched here
print('yay error');
rethrow;
} finally {
print('hello');
}
print('wait...');
only prints try
and doesn't throw anyting. The debugger really sees the error in the dart io files but (due to async gaps ?) the callstack doesn't trace back to http/my code. And step by step execution really reveals that the error happens res = await http.get(...);
@Hamada-Gado No, finally
will always run. So you can cross that idea off. 🙂
You can try it yourself:
void main() {
try {
throw Exception('Ded');
} finally {
print('Clean up');
}
}