Handling errors with futures

Flutter tips Published on

Working with asynchronous code and Futures is common in Dart and Flutter. It's important to handle potential errors properly.

A Basic Failing Function

Let's look at a simple Future function that throws an error:

Future<void> functionInError() async {
  throw "I am failing";
}

How NOT to Handle Errors

Avoid handling errors like this:

functionInError()
  .catchError((err) => print("error catched"))
  .then(
    (value) => print("success"),
    onError: (err) => print("I failed"),
  );
// Result: ------\n// error catched \n// success

Why? Because .catchError stops the error from going down the chain. The .then's onError won't be called, and you might get unexpected "success" results.

The Correct Way with .catchError (If You Need to Rethrow)

If you use .catchError but want the error to continue, rethrow it:

functionInError()
  .catchError((err) {
    print("error catched");
    throw err;
  })
  .then(
    (value) => print("success"),
    onError: (err) => print("I failed"),
  );
// Result: ------\n// error catched \n// I failed

This catches the error, does something, and then throws it again so the next onError can handle it.

Prefer Handling Errors in onError

Generally, it's better to handle errors directly in the onError callback within .then or use catchError only when you intend to stop the error propagation or transform it.

Chaining Futures and Errors

When you chain Futures, errors are passed down the chain to the latest available onError handler:

void main() {
  functionInError()
  .then((res) => workingFuture())
  .then((res) => print("ended"),
  onError: (err) => print("error catched") // This catches the error from functionInError()
  );
}

Future<void> workingFuture() async {
  print("working future");
}

Future<void> functionInError() async {
  throw "I am failing";
}
// Result:\n// error catched

Using try...catch with await

A clean way to handle errors with asynchronous code is using try...catch with the await keyword. This makes async code look and behave more like sync code.

void main() async {
  try {
    await functionInError();
  } catch (err) {
    print('I failed');
  }
}
// Result:\n// I failed

This approach is often easier to read and manage.

Choose the method that best fits your code structure and how you want errors to flow through your asynchronous operations.

Save 3 months of work

Create your app using our 6 years of making Flutter apps and more than 50+ apps

kickstarter for flutter apps

Frequently Asked Questions

Why shouldn't I put `.catchError` before `.then` with `onError`?

Using `.catchError` before `.then` with `onError` can stop the error from reaching the `onError` handler in `.then`, leading to unexpected behavior, like the 'success' part of the `.then` running.

When should I rethrow an error after catching it?

You should rethrow an error after catching it with `.catchError` if you want the error to continue propagating down the Future chain so that later `onError` handlers can also process it.

How does error handling work when chaining multiple Futures?

When chaining Futures with `.then()`, an error that occurs in one Future will skip the remaining `.then()` handlers and go directly to the next available `onError` handler in the chain.

Can I use `try...catch` with `await`?

Yes, using `try...catch` with `await` is a very common and often preferred way to handle errors in asynchronous code in Dart. It makes the code look and feel more like synchronous error handling.

Read more
You may also be interested in
Delegate widget design  blog card image
Delegate widget design
Published on 2025-05-12T09:03:59.853Z
Automatically create a new Apple Store version  blog card image
Automatically create a new Apple Store version
Published on 2025-05-12T09:03:39.549Z
ApparenceKit is a flutter template generator tool by Apparence.io © 2025.
All rights reserved