Skip to content

[bug]: setState() called during build - Exception on Browser Back Navigation #1184

@sbauly

Description

@sbauly

Describe the bug

When using the browser's built-in back navigation controls in a Stacked web application, the following exception is thrown:

══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞══
The following assertion was thrown while dispatching notifications for StackedRouterWeb:
setState() or markNeedsBuild() called during build.

This issue occurs using the default Stacked web template (unmodified code generated by the CLI).

What operating system do you use?

macOS

Information about the installed tooling

Flutter version: 3.35.4
Stacked CLI version: 1.15.4

stacked: 3.4.0
stacked_services: 1.1.0
stacked_generator: 1.3.3

Platform: Web (running on Google Chrome)

The issue has persisted even when updating stacked, stacked_services, and stacked_generator to their latest versions. The above versions are the default versions used after running stacked create app -t web.

Steps to reproduce the issue

  1. Create a new Stacked web app: stacked create app example -t web
  2. Run app in Google Chrome.
  3. Navigate from the HomeView to the UnknownView (or any view) using the RouterService, for example:
class HomeViewDesktop extends ViewModelWidget<HomeViewModel> {
  const HomeViewDesktop({super.key});

  @override
  Widget build(BuildContext context, HomeViewModel viewModel) {
    return Scaffold(
      body: Center(
          child: ElevatedButton(
              onPressed: () {
                locator<RouterService>().navigateToUnknownView();
              },
              child: const Text('Go to Unknown view'))),
    );
  }
}
  1. Navigate back using the browser’s back navigation control.
  2. Exception gets thrown.

Expected behavior

Browser back navigation should work without throwing exceptions, similar to programmatic navigation using locator<RouterService>().back(); - which works without issues.

Screenshots

No response

Additional Context

Here is the complete error:
══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
The following assertion was thrown while dispatching notifications for StackedRouterWeb:
setState() or markNeedsBuild() called during build.
This _RootRouter widget cannot be marked as needing to build because the framework is already in the
process of building widgets. A widget can be marked as needing to be built during the build phase
only if one of its ancestors is currently building. This exception is allowed because the framework
builds parent widgets before children, which means a dirty descendant will always be built.
Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
  _RootRouter
The widget which was currently being built when the offending call was made was:
  RouteNavigator

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 274:3       throw_
errors.dart:274
package:flutter/src/widgets/framework.dart 5279:9                                 <fn>
framework.dart:5279
package:flutter/src/widgets/framework.dart 5290:14                                markNeedsBuild
framework.dart:5290
package:flutter/src/widgets/framework.dart 1219:5                                 setState
framework.dart:1219
package:stacked/src/router/controller/nested_router_delegate.dart 176:7           [_handleRebuild]
nested_router_delegate.dart:176
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 118:77  tear
operations.dart:118
package:flutter/src/foundation/change_notifier.dart 435:24                        notifyListeners
change_notifier.dart:435
package:stacked/src/router/controller/routing_controller.dart 79:5                notifyAll
routing_controller.dart:79
package:stacked/src/router/controller/routing_controller.dart 884:7               [_removeRoute]
routing_controller.dart:884
package:stacked/src/router/controller/routing_controller.dart 866:5               removeRoute
routing_controller.dart:866
package:stacked/src/router/widgets/route_navigator.dart 77:17                     <fn>
route_navigator.dart:77
package:flutter/src/widgets/navigator.dart 3307:41                                handlePop
navigator.dart:3307
package:flutter/src/widgets/navigator.dart 4450:21                                [_flushHistoryUpdates]
navigator.dart:4450
package:flutter/src/widgets/navigator.dart 4378:5                                 [_updatePages]
navigator.dart:4378
package:flutter/src/widgets/navigator.dart 4013:7                                 didUpdateWidget
navigator.dart:4013
package:flutter/src/widgets/framework.dart 5893:55                                update
framework.dart:5893
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5884:11                                performRebuild
framework.dart:5884
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 5909:5                                 update
framework.dart:5909
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 6051:5                                 update
framework.dart:6051
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 6051:5                                 update
framework.dart:6051
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5884:11                                performRebuild
framework.dart:5884
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 5909:5                                 update
framework.dart:5909
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 5797:5                                 update
framework.dart:5797
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 6051:5                                 update
framework.dart:6051
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 6051:5                                 update
framework.dart:6051
package:flutter/src/widgets/framework.dart 3982:14                                updateChild
framework.dart:3982
package:flutter/src/widgets/framework.dart 5747:16                                performRebuild
framework.dart:5747
package:flutter/src/widgets/framework.dart 5884:11                                performRebuild
framework.dart:5884
package:flutter/src/widgets/framework.dart 5435:7                                 rebuild
framework.dart:5435
package:flutter/src/widgets/framework.dart 2695:14                                [_tryRebuild]
framework.dart:2695
package:flutter/src/widgets/framework.dart 2752:11                                [_flushDirtyElements]
framework.dart:2752
package:flutter/src/widgets/framework.dart 3056:17                                buildScope
framework.dart:3056
package:flutter/src/widgets/layout_builder.dart 271:5                             [_rebuildWithConstraints]
layout_builder.dart:271
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 118:77  tear
operations.dart:118
package:flutter/src/widgets/layout_builder.dart 334:28                            layoutCallback
layout_builder.dart:334
package:flutter/src/rendering/object.dart 4156:33                                 <fn>
object.dart:4156
package:flutter/src/rendering/object.dart 2881:9                                  <fn>
object.dart:2881
package:flutter/src/rendering/object.dart 1206:7                                  [_enableMutationsToDirtySubtrees]
object.dart:1206
package:flutter/src/rendering/object.dart 2880:7                                  invokeLayoutCallback
object.dart:2880
package:flutter/src/rendering/object.dart 4156:5                                  runLayoutCallback
object.dart:4156
package:flutter/src/widgets/layout_builder.dart 448:5                             performLayout
layout_builder.dart:448
package:flutter/src/rendering/object.dart 2610:7                                  [_layoutWithoutResize]
object.dart:2610
package:flutter/src/rendering/object.dart 1157:17                                 flushLayout
object.dart:1157
package:flutter/src/rendering/object.dart 1170:14                                 flushLayout
object.dart:1170
package:flutter/src/rendering/binding.dart 629:5                                  drawFrame
binding.dart:629
package:flutter/src/widgets/binding.dart 1261:13                                  drawFrame
binding.dart:1261
package:flutter/src/rendering/binding.dart 495:5                                  [_handlePersistentFrameCallback]
binding.dart:495
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 118:77  tear
operations.dart:118
package:flutter/src/scheduler/binding.dart 1434:7                                 [_invokeFrameCallback]
binding.dart:1434
package:flutter/src/scheduler/binding.dart 1347:9                                 handleDrawFrame
binding.dart:1347
package:flutter/src/scheduler/binding.dart 1200:5                                 [_handleDrawFrame]
binding.dart:1200
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/operations.dart 118:77  tear
operations.dart:118
lib/_engine/engine/platform_dispatcher.dart 1522:5                                invoke
platform_dispatcher.dart:1522
lib/_engine/engine/platform_dispatcher.dart 265:5                                 invokeOnDrawFrame
platform_dispatcher.dart:265
lib/_engine/engine/frame_service.dart 192:32                                      [_renderFrame]
frame_service.dart:192
lib/_engine/engine/frame_service.dart 99:9                                        <fn>
frame_service.dart:99
dart-sdk/lib/async/zone.dart 1849:54                                              runUnary
zone.dart:1849
dart-sdk/lib/async/zone.dart 1804:26                                              <fn>
zone.dart:1804
dart-sdk/lib/_internal/js_dev_runtime/patch/js_allow_interop_patch.dart 224:27    _callDartFunctionFast1
js_allow_interop_patch.dart:224

The StackedRouterWeb sending notification was:
  Root Router
════════════════════════════════════════════════════════════════════════════════════════════════════

Thank you to all the contributors for their hard work on this brilliant package!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions