61

Given the shortcode example below:

    ...
    print("1 parsing stuff");
    List<dynamic> subjectjson;
    try {
      subjectjson = json.decode(response.body);
    } on Exception catch (_) {
      print("throwing new error");
      throw Exception("Error on server");
    }
    print("2 parsing stuff");
    ...

I would expect the catch block to execute whenever the decoding fails. However, when a bad response returns, the terminal displays the exception and neither the catch nor the continuation code fires...

flutter: 1 parsing stuff
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: type
'_InternalLinkedHashMap<String, dynamic>' is not a subtype of type
'List<dynamic>'

What am I missing here?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Gorter
  • 2,162
  • 2
  • 17
  • 25
  • 1
    is there a reason why you aren't just doing '}catch(_){}' – F-1 Jun 28 '19 at 08:48
  • 1
    I am doing that now and that works, so I got rid of the on Exception clause.. I was under the assumption that incompatible types where an Exception as well. Should this not work? – John Gorter Jun 28 '19 at 08:51
  • What is the type that is actually caught? (e.g., do `catch (e) { print(e.runtimeType); }`). It sounds like a bug if `json.decode` throws something that isn't an `Exception` or an `Error`. – jamesdlin Jun 28 '19 at 12:54

8 Answers8

86

Functions can throw anything, even things that aren't an Exception:

void foo() {
  throw 42;
}

But the on Exception clause means that you are specifically catching only subclass of Exception.

As such, in the following code:

try {
  throw 42;
} on Exception catch (_) {
  print('never reached');
}

the on Exception will never be reached.

Rémi Rousselet
  • 256,336
  • 79
  • 519
  • 432
58

It is not a syntax error to have on Exception catch as someone else answered. However you need to be aware that the catch will not be triggered unless the error being thrown is of type Exception.

If you want to find out the exact type of the error you are getting, remove on Exception so that all errors are caught, put a breakpoint within the catch and check the type of the error. You can also use code similar to the following, if you want to do something for Exceptions, and something else for errors of all other types:

try {
  ...
} on Exception catch (exception) {
  ... // only executed if error is of type Exception
} catch (error) {
  ... // executed for errors of all types other than Exception
}
Ovidiu
  • 8,204
  • 34
  • 45
  • The Exception is the Top in hierarchy for every exception – Lakhwinder Singh Jun 28 '19 at 10:00
  • 6
    Thanks for the response, what makes it counter intuitive is that the error states: Unhandled Exception: type .... so this causes me to think that the error actually is an exception and since I am catching on the base class Exception, I expected the catch to run.. but it does not.. So I guess the terminal output says 'unhandled exception' but the type is actually not an exception at all :-) – John Gorter Jun 28 '19 at 11:09
10

Use:

try {
  ...
} on Exception catch (exception) {
  ... // only executed if error is of type Exception
} catch (error) {
  ... // executed for errors of all types other than Exception
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Android
  • 101
  • 1
  • 4
6

The rule is that exception handling should be from detailed exceptions to general exceptions in order to make the operation to fall in the proper catch block and give you more information about the error, like catch blocks in the following method:

Future<int> updateUserById(int userIdForUpdate, String newName) async {
  final db = await database;
  try {
    int code = await db.update('tbl_user', {'name': newName},
        whereArgs: [userIdForUpdate], where: "id = ?");
    return code;
  }
  on DatabaseException catch(de) {
    print(de);
    return 2;
  }
  on FormatException catch(fe) {
    print(fe);
    return 2;
  }
  on Exception catch(e) {
    print(e);
    return 2;
  }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mohsen Emami
  • 2,709
  • 3
  • 33
  • 40
5
    print("1 parsing stuff");
    List<dynamic> subjectjson;
    try {
      subjectjson = json.decode(response.body);
    } catch (_) { .   // <-- removing the on Exception clause
      print("throwing new error");
      throw Exception("Error on server");
    }
    print("2 parsing stuff");
    ...

This works, but what is the rationale behind this? Isn't the type inconsistency an Exception?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Gorter
  • 2,162
  • 2
  • 17
  • 25
  • This is not an answer. Can you move it to the question, please? (But ***without*** "Edit:", "Update:", or similar - the question should appear as if it was written today.) – Peter Mortensen Apr 08 '22 at 14:21
4

As everybody or most of the people said, try to know exactly what error you are getting:

try{
}
catch(err){
    print(err.runTimeType);
}

runTimeType will give you the type of data or exception you are getting or to put simple the exception itself. And then do whatever you want. (Like if you are not getting the exception of what you expected, then try to fix that issue or change the exception.)

Another option is to go with general form. Using the simple catch which will prompt every time.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
An Android
  • 149
  • 1
  • 6
1

The other possible reason for the catch bloc not to fire, as pointed out in this question, is missing brackets when throwing an exception.

Must write throw FormatException() instead of throw FormatException.

Chris
  • 839
  • 1
  • 12
  • 30
0

I had a issue with try catch but my problem was the API that I send http request, doesn't response of my request so that is why my request doesn't response anything and try catch didn't catch the error. So I suggest you to add timeout to your request so that if your api doesn't response your request after a while you can cancel your request with timeout. Here is an example how to use it;

try {
  final response = await http.post(Url).timeout(Duration(seconds: 5));
} catch (error) {
  print(error)
}
Timur Turbil
  • 1,145
  • 10
  • 13