flutterdartdiorxdart

The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type


I'm using new dart version >=2.12.0 <3.0.0 with null safety enabled.

I have added my code for reference.

MatchesService

import 'package:cric_app/AppUrls.dart';
import 'package:cric_app/features/home/match_model.dart';
import 'package:dio/dio.dart';
import 'package:rxdart/rxdart.dart';

class MatchesService {
  // ignore: close_sinks
  BehaviorSubject<List<MatchModel>> list = BehaviorSubject<List<MatchModel>>();

  Future<List<MatchModel>> getMatches() async {
    try {
      var matchList = await fetchMatches();
      list.add(matchList);
      return matchList;
    } catch (Exc) {
      print(Exc);
    }
  }

  Future<List<MatchModel>> fetchMatches() async {
    var dio = Dio();
    final response = await dio.post(AppUrls.getMatches);
    print(response.data);
    final body = response.data['matches'] as List;
    return body.map((dynamic json) {
      return MatchModel(
        id: json['id'] as int,
        date: json['date'] as String,
        dateGmt: json['dateTimeGMT'] as String,
        teamOne: json['team-1'] as String,
        teamTwo: json['team-2'] as String,
        tossWinnerTeam: json['toss_winner_team'] as String,
        matchStarted: json['matchStarted'] as bool,
        type: json['type'] as String,
        winnerTeam: json['winner_team'] as String,
      );
    }).toList();
  }
}

HomeScreen

import 'package:cric_app/components/match_card.dart';
import 'package:cric_app/features/home/match_model.dart';
import 'package:cric_app/features/home/matches_service.dart';
import 'package:cric_app/utils.dart';
import 'package:flutter/material.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  MatchesService matchesService = MatchesService();

  @override
  void initState() {
    matchesService.getMatches();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: primary_color,
      body: SingleChildScrollView(
        child: Container(
          margin: setMargin(15, 0, 15, 0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              SizedBox(
                height: 30,
              ),
              text('Matches', Colors.white, FontWeight.bold, 23),
              SizedBox(
                height: 2,
              ),
              text("Today's live matches", Colors.white, FontWeight.bold, 18),
              StreamBuilder<List<MatchModel>>(
                stream: matchesService.list,
                initialData: null,
                builder: (context, snapshot) {
                  if (snapshot.data != null) {
                    final list = snapshot.data as List;
                    return ListView.builder(
                      itemCount: list.length,
                      itemBuilder: (BuildContext context, int index) {
                        return matchCard(context, list[index]);
                      },
                    );
                  } else {
                    return Center(
                      child: text(
                        'No live matches now',
                        Colors.white,
                        FontWeight.bold,
                        16,
                      ),
                    );
                  }
                },
              ),
              SizedBox(
                height: 10,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

I get this error : The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type. Try adding either a return or a throw statement at the end.


Solution

  • In Dart, if your function has no return statement, that behaves the same as returning null. For example:

    dynamic doesntReturn() {
      // do nothing
    }
    print(doesntReturn());  // prints 'null'
    

    In your case, getMatches() is an async function that returns a Future<List<MatchModel>>. However, in your catch block, you don't return anything, causing an implicit return null:

      Future<List<MatchModel>> getMatches() async {
        try {
          var matchList = await fetchMatches();
          list.add(matchList);
          return matchList;
        } catch (Exc) {
          print(Exc);
        }
    
      // "return null" added implicitly
      }
    

    However, your function can't return null, since it has a return type of Future<List<MatchModel>>. It is complicated a bit by the async-ness, but the following synchronous code has the same behaviour:

    List<MatchModel> getMatches() {
      try {
        return _doSomeCalculation();
      } catch (e) {
        print(e);
      }
    }
    

    To fix this, you need to make sure that the implicit return null is never hit. You can either:

    1. rethrow the error, so getMatches() throws:
      Future<List<MatchModel>> getMatches() async {
        try {
          var matchList = await fetchMatches();
          list.add(matchList);
          return matchList;
        } catch (Exc) {
          print(Exc);
          rethrow;
        }
    
    1. return some other value, maybe an empty list?
    2. change getMatches to return a Future<List<MatchModel>?>
    3. loop forever (or some other expression with static type Never)

    I'd probably recommend option 1), but it depends on your use case