Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bad state: Cannot emit new states after calling close #3756

Closed
Lazizbek97 opened this issue Mar 7, 2023 · 13 comments
Closed

Bad state: Cannot emit new states after calling close #3756

Lazizbek97 opened this issue Mar 7, 2023 · 13 comments
Labels
question Further information is requested

Comments

@Lazizbek97
Copy link

Lazizbek97 commented Mar 7, 2023

Description
I've been using Cubit&Freezed for the app state management. I have wrapped MaterailApp with MultiBlocProvider and initialized all providers there. When the user logout, the app should remove all pages and push them to the login page. Here is the Problem. My main cubit is being disposed when i navigate with pushAndRemoveUntill() to login page, and after user login again, the app crashes with the error:

flutter: 
#0      BlocBase.emit (package:bloc/src/bloc_base.dart:96:9)
#1      MainCubit._updateCounterEnabled (package:billz_new_app/src/modules/main/cubit/main_cubit.dart:128:5)
#2      MainCubit.unleashInit.<anonymous closure> (package:billz_new_app/src/modules/main/cubit/main_cubit.dart:119:7)
#3      EventListener.call (package:events_emitter/listener.dart:61:33)
#4      EventEmitter.emitEvent (package:events_emitter/emitters/event_emitter.dart:93:34)

Expected Behavior
When the user logout and login, I want to refresh all cubits according to the user's credentials. without any crashes.

@Lazizbek97 Lazizbek97 added the bug Something isn't working label Mar 7, 2023
@tenhobi
Copy link
Collaborator

tenhobi commented Mar 7, 2023

Hey @Lazizbek97, could you send an example of how you setup your bloc provider and the MaterialApp?

@Gene-Dana Gene-Dana added question Further information is requested and removed bug Something isn't working labels Mar 9, 2023
@sanya-wadhwa
Copy link

I am not able to run void main for test cases as it is showing Bad state: Cannot add new events after calling close..
Any update or solution for this?
Here is the full error:

_dart:async _BroadcastStreamController.add
package:bloc/src/bloc.dart 99:24 Bloc.add
test/video_news/video_news_test.dart 128:16 main..
package:bloc_test/src/bloc_test.dart 208:20 testBloc.
===== asynchronous gap ===========================
dart:async _CustomZone.registerUnaryCallback
package:bloc_test/src/bloc_test.dart 201:7 testBloc.
dart:async runZonedGuarded
package:bloc_test/src/bloc_test.dart 199:9 testBloc
package:bloc_test/src/bloc_test.dart 156:13 blocTest.

Bad state: Cannot add new events after calling close_

@tenhobi
Copy link
Collaborator

tenhobi commented Mar 21, 2023

Hey @sanya-wadhwa, could you send us a minimal reproducible example with the error?

@MateusHBR
Copy link

MateusHBR commented Apr 4, 2023

I'm also encountering the same issue. In my implementation, I have a widget tree with a Screen widget that contains a MultiBlocProvider with a CustomTabBarView as its child. Each CustomTabBarView has some blocs that are necessary for it to works properly. In the dispose method of the widget, I add a new event to the blocs to perform some necessary cleanup.

However, when attempting to add an event to another bloc inside one of the blocs, a StateError is thrown because the event stream appears to be closed. This is problematic because the isClosed property of the bloc always returns false, as it only checks the StateStream and not the eventStream.

My Widget Tree:

Screen(
   TabBuilder(
     MultiBlocProvider(
       providers: [
           BlocProvider<BlocA>(),
           BlocProvider<BlocB>(),
           ...
       ],
       child: CustomTabBarView()
     )
   )
)

@tenhobi
Copy link
Collaborator

tenhobi commented Apr 4, 2023

Well sounds more like issues due to improper use. Either move blocs above the tab bar so they stay alive even when you switch tabs or use AutomaticKeepAliveClientMixin like this https://stackoverflow.com/a/61385007/3281252.

Send us a minimal reproducible example with the error you are facing so we can determine the exact issues.

@felangel
Copy link
Owner

Closing for now since there is no minimal reproduction sample. Feel free to provide one and we're happy to take a closer look, thanks! 👍

@farukprogrammer
Copy link

farukprogrammer commented Jan 30, 2024

@felangel

Simple Project to reproduce : https://github.com/farukprogrammer/bloc_8_1_2_issue
If you click back on second screen when still loading,
you will show in the console
image

The crash happen when there is still some process that will emit when finish, but the user is closing the screen first.
This is very very very general usage, and it shouldn't crash.
I'm trying to downgrade to use older version it didn't crash

@linhkiubo98
Copy link

I have same issue, do you have any solution?

@felangel felangel reopened this Oct 8, 2024
@felangel felangel added the needs triage This issue requires triage label Oct 8, 2024
@tenhobi
Copy link
Collaborator

tenhobi commented Oct 9, 2024

@farukprogrammer but this is expected as you dispose the route when you pres back button and therefore all of it's widgets as well, resulting in closing the bloc and this error if you emit something after it being closed.

Ideally you should check before emiting whether the bloc is still open or not.

if (isClosed) return;
emit(...);

However I agree that this could be done in the library itself and produce just some debug log (?) when this happends, since "almost everyone" I know has some kind of safeEmit function that basically does it for them. So I would like to open the discussion about whether we should add something like this to bloc itself or not, or any other alternatives.

Of course, ideally, making cancelable async operations would be better. #3069

@farukprogrammer
Copy link

hi @tenhobi thx for the feedback.
we know we can do safeEmit or safeAdd.

But you see, every year, there will be thousands of new programmer that learn flutter.
We don't want to give them crash using this awesome library right?

And when it goes to productions, I don't know how many users will be impacted, and we will responsible for that.
What happen if their life depend on that app? or they suicide because of the frustation?

Nahh maybe not.
But there is case people die because programmer introduce race condition in cancer tools software.

@tenhobi
Copy link
Collaborator

tenhobi commented Oct 14, 2024

I understand and in general I agree. But the same you have with Widgets and their context maybe not being mounted. It's just part of the design and reality. I am not entirely sure that not producing exceptions (which don't stop your program btw) and basiclly hiding wrong-usage that way would in fact benefit more than curent state. Because now you at least are super sure that issues in bloc logic get to you.

@farukprogrammer
Copy link

I'm sorry @tenhobi what do you mean by wrong usage? the way we handle it is by not emit when it's closed, which is should be handled by bloc, and it handled in previous versions. Make it crash instead of handling it inside bloc, make many programmer life getting more difficult, not sure if programmer have life though.

@felangel
Copy link
Owner

This isn't a crash -- the app will still continue to function correctly. It's an error indicating that the developer didn't correctly check if the bloc was closed before emitting a new state and it is consistent with how primitives like StreamController behave in Dart.

Closing this for now since it's been a while but if this is still an issue let me know and I'm happy to continue the discussion 👍

@felangel felangel removed the needs triage This issue requires triage label Nov 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

8 participants