Search code examples
dartexceptiontry-catchfilenotfoundexception

Dart: can't handle exceptions using the try catch block


I'm learning dart. I can't figure it out why the following dart code can't handle an exception. What wrong am I doing below?:

void main() {
  print(1);
  try {
    File file = File('random_path.txt');
    print(2);
    var contents = file.readAsString();
    print(3);
    contents.then((value) => print(value));
    print(4);
  } on FileSystemException catch (e) {
    print(5);
    print(e);
  } catch (e) {
    print(6);
    print(e);
  } finally {
    print(7);
  }

  print(8);
}

The file random_path.txt doesn't exist. I was expecting the on FileSystemException catch(e) to catch and print e. But that's not a case. Here is the output:

1
2
3
4
7
8
Unhandled exception:
FileSystemException: Cannot open file, path = 'random_path.txt' (OS Error: No such file or directory, errno = 2)
#0      _File.open.<anonymous closure> (dart:io/file_impl.dart:356:9)
<asynchronous suspension>

Solution

  • You need to handle the error that is reported by the contents future, and forwarded to the future returned by then.

    That means either adding an error handler yourself:

      contents.then(print).catchError((e, s) {
        print("Future error: $e\n$s");
      }); // Catches errors from `contents` or thrown by `print`.
    
    // or
    
      contents.then(print, onError: (e, s) {
        print("Future error: $e\n$s");
      }); // Won't catch error thrown by `print`.
    

    Or using an async function to handle the future using await, which is the recommended approach:

    void main() async { // <- marked as async so you can use `await`.
      print(1);
      try {
        File file = File('random_path.txt');
        print(2);
        Future<String> contents = file.readAsString();
        print(3);
        var value = await contents; // <- await gets value, or rethrows error
        print(value);
        print(4);
      } on FileSystemException catch (e) {
        print(5);
        print(e);
      } catch (e) {
        print(6);
        print(e);
      } finally {
        print(7);
      }
      print(8);
    }
    

    In general, always use async functions and await to deal with futures. Using the .then API is mainly for low-level code which integrates different asynchronous computations, and has to wait for more than one thing at a time. It's what's being used internally to build a good Future based API that you can just await on. And you should just await when you can.