Flutter http exception not throw on another try catch block - flutter

I get into this weird exception which keeps on coming and freezing my app.
I am try to handle SocketException and TimeOutException in http package with provider package.
class Auth with ChangeNotifier{
..........
Future<User> getUser(String id) async {
try {
final user = (await http.post("${Domain.ADDRESS}/user",
headers: {"auth-token": _token}, body: {"userId": id}))
.body;
} on SocketException {
throw HttpException("DISCONNECTED");
} on TimeoutException {
throw HttpException("TIMEOUT");
} catch (error) {
print(error);
throw HttpException("SOMETHING_WENT_WRONG");
}
notifyListeners();
return userdata;
}
......
}
when internet in not connected application freezing at
on SocketException {
throw HttpException("DISCONNECTED"); <------------ Exception has occurred.
HttpException (DISCONNECTED)
But I handle this on next screen
#override
Future<void> didChangeDependencies() async {
......
setState(() {
isLoading = true;
});
try{
user= await Provider.of<Auth>(context)
.getUser(Provider.of<Auth>(context).userId);
if (this.mounted) {
setState(() {
isLoading = false;
});
}
}on HttpException catch(error){
if(error.toString().contains("DISCONNECTED")){
Scaffold.of(context).showSnackBar(SnackBar(content: Text("Please check your internet
connection"),));
}
}catch(error){
print(error);
}
super.didChangeDependencies();
}
Custom HttpException.dart
class HttpException implements Exception {
final String message;
HttpException(this.message);
#override
String toString() {
return message;
}
}

So if I understand you right, your IDE pauses when the exception is thrown, even though you catch it correctly.
Can you tell me what happens after resuming / unpausing the IDE that you're using, does it behave as expected and print this?
if(error.toString().contains("DISCONNECTED")){
Scaffold.of(context).showSnackBar(SnackBar(content: Text("Please check your internet
connection"),));
Because if it does, that means that you probably have the Breakpoints setting on All Exceptions and not only Uncaught Exceptions.

I also had this problem and I found out that it was due to a bugged flutter beta/dev version that I had.
Solution
I fixed it by changing the channel to stable and upgrading to the newest version.
flutter channel stable
flutter upgrade
If you want, you can also change the channel to master to have the newest features of flutter. But I would really suggest using the stable channel, since it is more stable and beacause a new stable build was just recently released.
Here's a link to the issue that you're encountering:
https://github.com/flutter/flutter/issues/66488

Related

How to catch a flutter cloud firestore permission-denied error with a stream

I'm noticing an issue where I can't catch a permission-denied error from cloud firestore with a stream in a flutter app.
I have this repository which is supposed to generate a stream of documents, and I have my security rules set to prevent all reading of documents.
I try catching all Exceptions, and then catching everything, and while breakpoints show an Exception is being thrown for 'permission-denied' from Cloud Firestore, the method never hits either of the catch blocks, and I get a message in VS Code saying I had an unhandled exception. Is there anything I'm missing here?
#override
Stream<List<Habit>> watchMyActiveHabits() async* {
try {
final userDoc = await _firestore.userDocument();
yield* userDoc
.collection('habits')
.withConverter(
fromFirestore: (snapshot, _) => Habit.fromJson(snapshot.data()!),
toFirestore: (habit, _) => habit.toJson(),
)
.where('active', isEqualTo: true)
.snapshots()
.map((snapshot) => snapshot.docs.map((doc) => doc.data()).toList());
} on Exception catch (e) {
_log.e('Exception: $e');
rethrow;
} catch (e) {
_log.e('Unknown error: $e');
rethrow;
}
}
I am using the Flutter bloc pattern and have this bloc that triggers that method and is supposed to return a state if an exception occurs, but it just hangs in the loadInProgress state:
HabitWatcherBloc(this._habitRepository) : super(const _Initial()) {
on<_Started>((event, emit) {
emit(const HabitWatcherState.loadInProgress());
try {
_habitStreamSubscription =
_habitRepository.watchMyActiveHabits().listen((habits) {
emit(HabitWatcherState.loadSuccess(habits));
});
} on Exception catch (e) {
emit(HabitWatcherState.loadFailure(e));
}
});
}
}

Error debugging Flutter in Visual Studio Code

When debugging an async function, when there is a line with await, it can't debug the next line and I never get to know the response body. If I make a break point either. And this is happening to me in all lines with await.
#override
Future getCountries() async {
try {
final response = await httpCache(
'$domain/wp-json/api/flutter_user/get_countries'.toUri()!);
var body = convert.jsonDecode(response.body);
return body;
} catch (err) {
rethrow;
}
}
Know if there is any configuration to debug asynchronous functions in Flutter with VSCode.

Flutter custom exception not throwing

I upgraded Flutter from version 2.0.2 to version 2.2.2 and now the custom exceptions that are thrown from a Future function are not being catch.
For example, I got this Future function, where I call another Future that does a server request and returns back the response or throws a custom exception (ApiException) in case of error:
static Future<bool> signUpCustomerRequest(Map<String, dynamic> params) async {
try {
// Here we call this Future function that will do a request to server API.
dynamic _response = await _provider.signUpCustomer(params);
if (_response != null) {
updateUserData(_response);
return true;
}
return false;
} on ApiException catch(ae) {
// This custom exception is not being catch
ae.printDetails();
rethrow;
} catch(e) {
// This catch is working and the print below shows that e is Instance of 'ApiException'
print("ERROR signUpCustomerRequest: $e");
rethrow;
} finally {
}
}
And this is the Future function that does the request to server and throws the ApiException:
Future<User?> signUpCustomer(Map<String, dynamic> params) async {
// POST request to server
var _response = await _requestPOST(
needsAuth: false,
path: routes["signup_client"],
formData: params,
);
// Here we check the response...
var _rc = _response["rc"];
switch(_rc) {
case 0:
if (_response["data"] != null) {
User user = User.fromJson(_response["data"]["user"]);
return user;
}
return null;
default:
print("here default: $_rc");
// And here we have the throw of the custom exception (ApiException)
throw ApiException(getRCMessage(_rc), _rc);
}
}
Before upgrading to Flutter 2.2.2 the catch of custom exceptions worked perfectly. Did something change on this Flutter version? Am I doing something wrong?
Thanks!
I was able to reproduce your bug with the following code:
class ApiException implements Exception {
void printDetails() {
print("ApiException was caught");
}
}
Future<void> doSomething() async {
await Future.delayed(Duration(seconds: 1));
throw ApiException();
}
void main() async {
try {
await doSomething();
} on ApiException catch (ae) {
ae.printDetails();
} catch (e) {
print("Uncaught error: $e"); // This line is printed
}
}
There's an open issue on the dart sdk, which I think might be related, though I'm not sure: https://github.com/dart-lang/sdk/issues/45952.
In any case, I was able to correct the error by returning a Future.error, instead of throwing the error directly:
class ApiException implements Exception {
void printDetails() {
print("ApiException was caught"); // This line is printed
}
}
Future<void> doSomething() async {
await Future.delayed(Duration(seconds: 1));
return Future.error(ApiException());
}
void main() async {
try {
await doSomething();
} on ApiException catch (ae) {
ae.printDetails();
} catch (e) {
print("Uncaught error: $e");
}
}

Exception handling in flutter + VS Code

I have a simple functionality for user authentication. When user clicks Login buttonm than callback calls login method from SecurityBloc which in its turn calls execute method of ApiProvider.
If user enter wrong password than method _handleResponse throws ApiException with error description which I am expecting to be catched in method login of SecurityBloc. And it works as expected when I run project under the web. I see snackbar with error message.
The problem occurred when I run project under Android. When user enter wrong password than VS Code (I use it) stops on line with throw ApiException('invalid authentication response');, i.e. debugger thinks that this exception is unhandled! But it is catched and handled (see code). When I click button continue on debugger control panel, the highlighted row jumps over the code and at the end I see the error message in snackbar.
So is it possible to skip (fix) this situation? Maybe is it knowing bug and there is a workaround?
P.S. If I checked off the "Uncaught exception" checkbox looks fine but it is not the case because now I may pass really uncaucht exceptions.
Any ideas?
class ApiProvider {
/// Executes HTTP request
Map<String, dynamic> execute(url, query, ...) async {
final response = await http.post(url,query:query);
return _handleResponse(response);
}
/// Parses HTTP response
Map<String, dynamic> _handleResponse(Response response) {
if (!response.contains('user')) {
throw ApiException('invalid password');
}
... // other statements
}
}
class SecurityBloc {
Future<AuthEvent> login(String user, String password) async {
try {
final data = api.execute()
if (data == null) {
throw ApiException('invalid authentication response');
}
final token = _parseData(data); // Can throws FormatException
return AuthEvent.ok(token);
} on ClientException catch(e) {
return AuthEvent.error(e.message);
} on FormatException catch(e) {
return AuthEvent.error(e.message);
} on ApiException catch(e) {
return AuthEvent.error(e.message);
}
}
}
class _LoginState extends State<Login> {
final securityBloc = SecutiryBloc();
#override
Widget build(BuildContext context) {
return
...
FlatButton(
child: Text('Login'),
onPressed: () async {
final authEvent = await securityBloc.login(...);
if (authEvent.failed) {
ScaffoldMessenger.of(context).showSnackbar(...); // Show authentication error
} else {
// access granted
}
},
),
...
}
Please see this https://github.com/FirebaseExtended/flutterfire/issues/3475 that I raised...if you follow the thread and the link at the end it would appear a fix was posted to master in early October....don't know when it will make it through the releases to stable. Basically though, this is an issue that impacts the IDE and won't manifest itself in the released app on a device.

How to catch cloud functions onCall functions.https.HttpsError by Flutter with cloud_functions package

I'm using Flutter cloud_functions package and Cloud functions. I want to catch functions.https.HttpsError by on CloudFunctionsException (Client side) I can't catch functions.https.HttpsError with Flutter no matter what I intentionally throw.
Is it impossible to catch functions.https.HttpsError throw by cloud functions package with CloudFunctionsException?
Help me.
cloud functions
export const sampleFunctions = functions.region(REGION).https.onCall((data, context) => {
if (!data.hoge) throw new functions.https.HttpsError('failed-precondition', 'some reason');
return { response: data.fuga };
});
dart
Future<dynamic> sampleFunction() async {
final _cloudFunctions = CloudFunctions(region: 'asia-northeast1');
final _sampleFunctions = _cloudFunctions.getHttpsCallable(
functionName: 'sampleFunctions',
);
try {
final resp = await _sampleFunctions.call(<String, dynamic>{
'fuga': 'fuga',
});
print(resp);
} on CloudFunctionsException catch (e) {
print(e.code);
print(e.message);
}
}
There is a call function implementation in Dart docs. If you take a look on it CloudFunctionsException is thrown only when exception property code == 'functionsError'.
With functions.https.HttpsError you are code from the first parameter( 'failed-precondition' in the example). Unfortunately HttpError has limited possible values of error codes and "functionsError" is not in the list.
So it seems that it will not work this way.
I hope it will help!