The return type ‘void’ isn’t assignable to ‘FutureOr’, as required by ‘Future.catchError’

The documentation for Future.catchError could be a lot clearer, but the relevant part is:

onError is called with the error and possibly stack trace, and the returned future is completed with the result of this call in exactly the same way as for then‘s onError.

Cross-referencing to the documentation for Future.then, the relevant portion is:

The onError callback must return a value or future that can be used to complete the returned future, so it must be something assignable to FutureOr<R>.

Since File.readAsString returns a Future<String>, your catchError callback also must return a Future<String>. Examples of doing that:

File("foo.txt").readAsString().catchError((e) {
  print(e);
  return Future.value('');
});

File("foo.txt").readAsString().catchError((e) async {
  print(e);
  return '';
});

Logically, this makes sense; because given:

String value = await File("foo.txt").readAsString().catchError(...);

then if readAsString succeeds, value should be assigned a String. If it fails, since you catch the exception without rethrowing it, value still needs to be assigned a String.

Put another way, your code is equivalent to:

Future<String> readFoo() async {
  try {
    return await File("foo.txt").readAsString();
  } catch (e) {
    print(e);
  }
  // Oops, missing return value.
}

In general, I strongly recommend using async/await with trycatch instead of using .catchError, which would avoid this confusion.

Leave a Comment