onError<E extends Object>  method 
- FutureOr<T> handleError(- E error,
- StackTrace stackTrace
 
- bool test(- E error
 
Handles errors on this future.
Catches errors of type E that this future complete with.
If test is supplied, only catches errors of type E
where test returns true.
If E is Object, then all errors are potentially caught,
depending only on a supplied test.toString()
If the error is caught,
the returned future completes with the result of calling handleError
with the error and stack trace.
This result must be a value of the same type that this future
could otherwise complete with.
For example, if this future cannot complete with null,
then handleError also cannot return null.
Example:
Future<T> retryOperation<T>(Future<T> operation(), T onFailure()) =>
    operation().onError<RetryException>((e, s) {
      if (e.canRetry) {
        return retryOperation(operation, onFailure);
      }
      return onFailure();
    });
If handleError throws, the returned future completes
with the thrown error and stack trace,
except that if it throws the same error object again,
then it is considered a "rethrow"
and the original stack trace is retained.
This can be used as an alternative to skipping the
error in test.
Example:
// Unwraps an exceptions cause, if it has one.
someFuture.onError<SomeException>((e, _) {
  throw e.cause ?? e;
});
// vs.
someFuture.onError<SomeException>((e, _) {
  throw e.cause!;
}, test: (e) => e.cause != null);
If the error is not caught, the returned future completes with the same result, value or error, as this future.
This method is effectively a more precisely typed version of Future.catchError. It makes it easy to catch specific error types, and requires a correctly typed error handler function, rather than just Function. Because of this, the error handlers must accept the stack trace argument.
Implementation
Future<T> onError<E extends Object>(
  FutureOr<T> handleError(E error, StackTrace stackTrace), {
  bool test(E error)?,
}) {
  FutureOr<T> onError(Object error, StackTrace stackTrace) {
    if (error is! E || test != null && !test(error)) {
      // Counts as rethrow, preserves stack trace.
      throw error;
    }
    return handleError(error, stackTrace);
  }
  if (this is _Future<Object?>) {
    // Internal method working like `catchError`,
    // but allows specifying a different result future type.
    return unsafeCast<_Future<T>>(this)._safeOnError<T>(onError);
  }
  return this.then<T>((T value) => value, onError: onError);
}