'Future.then must return a value of the returned future's type

I'm continuously getting this error

Unhandled Exception: Invalid argument(s) (onError): The error handler of Future.then must return a value of the returned future's type

NetworkApi

class NetworkApi {
  NetworkApi(this.url);

  final String url;

  Future getData() async {
    http.Response response = await http.get(Uri.parse(url));

    if (response.statusCode == 200) {
      String data = response.body;

      return jsonDecode(data);
    } else {
      if (kDebugMode) {
        print(response.statusCode);
      }
    }
  }
}

ApiSelector

class ApiSelector {
  Future getApiData({String categoryName = ""}) async {
    late NetworkApi _api;
    if(categoryName != ""){
     _api = NetworkApi('api');
    }else{
      _api = NetworkApi('myapi');
    }
    var Data = await _api.getData();
    if (Data['status'] == 'error') {
      throw'Error while fetching data';
    }
    return MyModel.fromJson(Data);
  }
}

MyFunction To Call API selector

  Future getDataFromApi() async {
    await _apiSelector
        .getApiData(categoryName: "Some Category")
        .then((value) {
      myModel = value as MyModel;
      print(myModel);
      return value;
    } ,onError: (error) {
     print(error);
      return error;
    },);
  }

I have tried everything to solve this issue. May you please guide me what to do. I have even tried with exception handling but still getting this error.



Solution 1:[1]

Specify the Future of return type like Future<dynamic>

NetworkApi

class NetworkApi {
  NetworkApi(this.url);

  final String url;

  Future<dynamic> getData() async {
    http.Response response = await http.get(Uri.parse(url));

    if (response.statusCode == 200) {
      String data = response.body;

      return jsonDecode(data);
    } else {
      if (kDebugMode) {
        print(response.statusCode);
      }
    }
  }
}

ApiSelector

class ApiSelector {
  Future<MyModel> getApiData({String categoryName = ""}) async {
    late NetworkApi _api;
    if(categoryName != ""){
     _api = NetworkApi('api');
    }else{
      _api = NetworkApi('myapi');
    }
    var Data = await _api.getData();
    if (Data['status'] == 'error') {
      throw'Error while fetching data';
    }
    return MyModel.fromJson(Data);
  }
}

MyFunction To Call API selector

  Future<MyModel?> getDataFromApi() async {
   try {
     var value = await _apiSelector.getApiData(categoryName: "Some Category");
     myModel = value as MyModel;
     return myModel;

   } catch(error) {
      print(error);
      return error;
   }
  }

Solution 2:[2]

The problem is in getDataFromApi:

Future getDataFromApi() async {
    await _apiSelector
        .getApiData(categoryName: "Some Category")
        .then((value) {
      myModel = value as MyModel;
      print(myModel);
      return value;
    } ,onError: (error) {
     print(error);
      return error;
    },);
  }

As explained by the error message, your onError handler fails to return the same type as returned by Future.then's success path. (See https://stackoverflow.com/a/66397222/ for an explanation.) This normally would be a compile-time error but ends up being a runtime one because getDataFromApi is declared to return a Future (equivalent to Future<dynamic> instead of Future<MyModel>.

Using the raw Future API with error callbacks (whether with Future.then's onError argument or with Future.catchError) is rather confusing to use directly. You're already using await, so there's no reason for you to be using Future.then. With await, you can use try-catch instead, which makes the problem much clearer:

Future<MyModel> getDataFromApi() async {
  try {  
    var myModel = await _apiSelector.getApiData(categoryName: "Some Category");
    print(myModel);
    return myModel;
  } catch (error) {
    print(error);
    return error; // WRONG: This is not a `MyModel`!
  }
}

To fix this, either your catch block needs to return a MyModel or must throw an exception.

Solution 3:[3]

class ApiSelector {
  Future getApiData({String categoryName = ""}) async {
    late NetworkApi _api;
    if(categoryName != ""){
     _api = NetworkApi('api');
    }else{
      _api = NetworkApi('myapi');
    }
    var Data = await _api.getData();
    if (Data['status'] == 'error') {

    //I had to replace throw with Future.value Now All Errors are gone.
             return Future.value( 'Error while fetching data');
    }
    return MyModel.fromJson(Data);
  }
}

I hope this will also help others who will face this kind of error sometime in future.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3