A future can complete in the error state. Future.error(...) produces one directly, and .catchError(fn) runs fn on the error to produce a fresh value. Because both branches use already-completed futures, the example has no timers or external events.

Program

Play the program to await one successful call and one recovered call.

future_error.dart
Replay: real traced execution (multi-file project)
Future<int> parseScore(String input) {
  if (input == 'ok') return Future.value(9);
  return Future.error(FormatException('not a score'));
}

Future<int> safeScore(String input) {
  return parseScore(input).catchError((_) => 0);
}

Future<void> main() async {
  var good = await safeScore('ok');
  var bad = await safeScore('???');
  print('good=$good bad=$bad');
}
  1. return ← Future.value(9)

    1Future<int> parseScore(String input) {2  if (input == 'ok') return Future.value(9);3  return Future.error(FormatException('not a score'));
    values this stepFuture.value(9)returnokinput
  2. path ← no error, pass through

    6Future<int> safeScore(String input) {7  return parseScore(input).catchError((_) => 0);8}
    values this stepno error, pass throughpathFuture.value(9)future
  3. good ← 9

    10Future<void> main() async {11  var good = await safeScore('ok');12  var bad = await safeScore('???');
    values this step9good
  4. return ← Future.error(FormatException)

    2  if (input == 'ok') return Future.value(9);3  return Future.error(FormatException('not a score'));4}
    values this stepFuture.error(FormatException)return???input
  5. path ← recovered with 0

    6Future<int> safeScore(String input) {7  return parseScore(input).catchError((_) => 0);8}
    values this steprecovered with 0pathFuture.errorfuture
  6. bad ← 0

    11var good = await safeScore('ok');12var bad = await safeScore('???');13print('good=$good bad=$bad');
    values this step0bad
  7. print('good=$good bad=$bad');

    12  var bad = await safeScore('???');13  print('good=$good bad=$bad');14}
    outputgood=9 bad=0
    values this step9good0bad
Future.error `Future.error(...)` is an already-completed failure; awaiting it throws.
catchError `.catchError(fn)` runs `fn` on the error and returns a fresh future carrying its result.
await unwraps `await safeScore(...)` yields the recovered value, so `main` never sees an exception.