[Solved] Dart: Error while creating bloc - "Tried to read a provider that threw during the creation of its value. "

Question

Asked by Dawid T on December 22, 2021 (source).

I'm learning bloc from a deprecated tutorial and I have troubles with making it work. The error which I receive is:

 Error while creating GetRandomNumberTrivia
(...)
The following StateError was thrown building InheritedProvider<NumberTriviaBloc>:
Bad state: Tried to read a provider that threw during the creation of its value.
The exception occurred during the creation of type NumberTriviaBloc.

Full error: https://pastebin.com/CpvrFZ1v

This is my bloc file:

const String serverFailureMessage = 'Server failure';
const String cacheFailureMessage = 'Cache failure';
const String invalidInputMessage =
    'Invalid input, the number should be positive integer or zero';

class NumberTriviaBloc extends Bloc<NumberTriviaEvent, NumberTriviaState> {
  final GetConcreteNumberTrivia getConcreteNumberTrivia;
  final GetRandomNumberTrivia getRandomNumberTrivia;
  final InputConverter inputConverter;

  NumberTriviaBloc(
      {required this.getConcreteNumberTrivia,
      required this.getRandomNumberTrivia,
      required this.inputConverter})
      : super(Empty()) {

    on<GetTriviaForConcreteNumber>(
      (event, emit) async {
        final inputEither =
            inputConverter.stringToUnsignedInteger(event.numberString);
        inputEither.fold((l) =>  emit(Error(message: invalidInputMessage)),
            (r)  async {
          emit(Loading());
          final failureOrTrivia = await getConcreteNumberTrivia(Params( number: r));
          //todo message
          failureOrTrivia.fold((l) => emit(Error(message: 'problem message')),
              (r) => emit(Loaded(trivia: r)));
        });
      },
    );

    on<GetTriviaForRandomNumber>(
      (event, emit) async {
        emit(Loading());
        final failureOrTrivia = await getRandomNumberTrivia(NoParams());

        failureOrTrivia.fold((l) => emit(Error(message: "Invalid input")),
            (r) async {
          emit(Loaded(trivia: r));

        });
      },
    );
  }
}

Here's code which I mimic: https://github.com/ResoCoder/flutter-tdd-clean-architecture-course/blob/master/lib/features/number_trivia/presentation/bloc/number_trivia_bloc.dart

That's how I'm using BlocProvider:

class NumberTriviaPage extends StatelessWidget {
  const NumberTriviaPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
(...)
      body: buildBody(context),
    );
  }
}

BlocProvider<NumberTriviaBloc> buildBody(BuildContext context) {
  return BlocProvider(
    create: (_) =>  sl<NumberTriviaBloc>(),
    child: Center(
      child: Padding(
        padding: const EdgeInsets.all(10),
        child: Column(
          children: <Widget>[
            const SizedBox(height: 10),
             BlocBuilder<NumberTriviaBloc, NumberTriviaState>(
              builder: (context, state) {
                if (state is Empty) {
                  return const MessageDisplay(
                    message: 'Start searching!',
                  );
                } else if (state is Loading) {
                  return const LoadingWidget();
                } else if (state is Loaded) {
                  return TriviaDisplay(numberTrivia: state.trivia);
                } else if (state is Error) {
                  return MessageDisplay(
                    message: state.message);
                }else{
                  return Container();
                }
              },
            ),
            const TriviaControls(),
          ],
        ),
      ),
    ),
  );
}

And that's how I init bloc, by using dependency injection:

import 'injection_container.dart' as di;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await di.init();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
(...)
      home: const NumberTriviaPage(),
    );
  }
}
//sl = serviceLocator
final sl = GetIt.instance;

Future<void> init() async {
  //serviceLocator call looking for are registered types/dependencies
  sl.registerFactory(() => NumberTriviaBloc(getConcreteNumberTrivia: sl(), getRandomNumberTrivia: sl(), inputConverter: sl()));
(...)

}

According to error the problem seems to lays somewhere in GetRandomNumberTrivia, but I implemented it in same way as similar GetConcreteNumberTrivia and I do not see what can be wrong here.

Answer

Question answered by Mckenzie (source).

In class GetRandomNumberTrivia I added typing NumberTriviaRepository for the field repository and the code compiled.

BLOC DART FLUTTER
SHARE: