Skip to content

NestedScrollView example throws error #183199

Closed

Description

@treeplate

Steps to reproduce

  1. flutter create --sample=widgets.NestedScrollView.1 mysample
  2. cd mysample
  3. flutter run
  4. scroll down some
  5. (with trackpad) scroll up a bit, then quickly scroll right

Expected results

no error

Actual results

══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown while notifying status listeners for AnimationController:
The provided ScrollController is attached to more than one ScrollPosition.
The Scrollbar requires a single ScrollPosition in order to be painted.
When the scrollbar is interactive, the associated ScrollController must only have one ScrollPosition
attached.
The provided ScrollController cannot be shared by multiple ScrollView widgets.

When the exception was thrown, this was the stack:
#0      RawScrollbarState._debugCheckHasValidScrollPosition.<anonymous closure> (package:flutter/src/widgets/scrollbar.dart:1530:9)
#1      RawScrollbarState._debugCheckHasValidScrollPosition (package:flutter/src/widgets/scrollbar.dart:1558:6)
#2      RawScrollbarState._validateInteractions (package:flutter/src/widgets/scrollbar.dart:1467:14)
#3      AnimationLocalStatusListenersMixin.notifyStatusListeners (package:flutter/src/animation/listener_helpers.dart:242:19)
#4      AnimationController._checkStatusChanged (package:flutter/src/animation/animation_controller.dart:937:7)
#5      AnimationController._startSimulation (package:flutter/src/animation/animation_controller.dart:870:5)
#6      AnimationController._animateToInternal (package:flutter/src/animation/animation_controller.dart:687:12)
#7      AnimationController.reverse (package:flutter/src/animation/animation_controller.dart:521:12)
#8      RawScrollbarState._maybeStartFadeoutTimer.<anonymous closure> (package:flutter/src/widgets/scrollbar.dart:1611:37)
#12     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)
(elided 3 frames from class _Timer and dart:async-patch)

The AnimationController notifying status listeners was:
  AnimationController#18197(◀ 1.000)
════════════════════════════════════════════════════════════════════════════════════════════════════

Code sample

Code sample
import 'package:flutter/material.dart';

/// Flutter code sample for [NestedScrollView].

void main() => runApp(const NestedScrollViewExampleApp());

class NestedScrollViewExampleApp extends StatelessWidget {
  const NestedScrollViewExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: NestedScrollViewExample());
  }
}

class NestedScrollViewExample extends StatelessWidget {
  const NestedScrollViewExample({super.key});

  @override
  Widget build(BuildContext context) {
    final List<String> tabs = <String>['Tab 1', 'Tab 2'];
    return DefaultTabController(
      length: tabs.length, // This is the number of tabs.
      child: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            // These are the slivers that show up in the "outer" scroll view.
            return <Widget>[
              SliverOverlapAbsorber(
                // This widget takes the overlapping behavior of the SliverAppBar,
                // and redirects it to the SliverOverlapInjector below. If it is
                // missing, then it is possible for the nested "inner" scroll view
                // below to end up under the SliverAppBar even when the inner
                // scroll view thinks it has not been scrolled.
                // This is not necessary if the "headerSliverBuilder" only builds
                // widgets that do not overlap the next sliver.
                handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                  context,
                ),
                sliver: SliverAppBar(
                  title: const Text(
                    'Books',
                  ), // This is the title in the app bar.
                  pinned: true,
                  expandedHeight: 150.0,
                  // The "forceElevated" property causes the SliverAppBar to show
                  // a shadow. The "innerBoxIsScrolled" parameter is true when the
                  // inner scroll view is scrolled beyond its "zero" point, i.e.
                  // when it appears to be scrolled below the SliverAppBar.
                  // Without this, there are cases where the shadow would appear
                  // or not appear inappropriately, because the SliverAppBar is
                  // not actually aware of the precise position of the inner
                  // scroll views.
                  forceElevated: innerBoxIsScrolled,
                  bottom: TabBar(
                    // These are the widgets to put in each tab in the tab bar.
                    tabs: tabs.map((String name) => Tab(text: name)).toList(),
                  ),
                ),
              ),
            ];
          },
          body: TabBarView(
            // These are the contents of the tab views, below the tabs.
            children: tabs.map((String name) {
              return SafeArea(
                top: false,
                bottom: false,
                child: Builder(
                  // This Builder is needed to provide a BuildContext that is
                  // "inside" the NestedScrollView, so that
                  // sliverOverlapAbsorberHandleFor() can find the
                  // NestedScrollView.
                  builder: (BuildContext context) {
                    return CustomScrollView(
                      // The "controller" and "primary" members should be left
                      // unset, so that the NestedScrollView can control this
                      // inner scroll view.
                      // If the "controller" property is set, then this scroll
                      // view will not be associated with the NestedScrollView.
                      // The PageStorageKey should be unique to this ScrollView;
                      // it allows the list to remember its scroll position when
                      // the tab view is not on the screen.
                      key: PageStorageKey<String>(name),
                      slivers: <Widget>[
                        SliverOverlapInjector(
                          // This is the flip side of the SliverOverlapAbsorber
                          // above.
                          handle:
                              NestedScrollView.sliverOverlapAbsorberHandleFor(
                                context,
                              ),
                        ),
                        SliverPadding(
                          padding: const EdgeInsets.all(8.0),
                          // In this example, the inner scroll view has
                          // fixed-height list items, hence the use of
                          // SliverFixedExtentList. However, one could use any
                          // sliver widget here, e.g. SliverList or SliverGrid.
                          sliver: SliverFixedExtentList.builder(
                            // The items in this example are fixed to 48 pixels
                            // high. This matches the Material Design spec for
                            // ListTile widgets.
                            itemExtent: 48.0,
                            // The itemCount of the SliverFixedExtentList.builder
                            // specifies how many children this inner list
                            // has. In this example, each tab has a list of
                            // exactly 30 items, but this is arbitrary.
                            itemCount: 30,
                            itemBuilder: (BuildContext context, int index) {
                              // This builder is called for each child.
                              // In this example, we just number each list item.
                              return ListTile(title: Text('Item $index'));
                            },
                          ),
                        ),
                      ],
                    );
                  },
                ),
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration https://github.com/user-attachments/assets/2ae9b439-0732-451d-b55c-39f86bb67441

Logs

Logs
Connected devices:
macOS (desktop) • macos  • darwin-arm64   • macOS 26.3 25D125 darwin-arm64
Chrome (web)    • chrome • web-javascript • Google Chrome 145.0.7632.119

No wireless devices were found.

[1]: macOS (macos)
[2]: Chrome (chrome)
Please choose one (or "q" to quit): 1
Launching lib/main.dart on macOS in debug mode...
Building macOS application...                                           
✓ Built build/macos/Build/Products/Debug/mysample.app
2026-03-03 17:49:18.821 mysample[6737:609322] Running with merged UI and platform thread. Experimental.
Failed to foreground app; open returned 1
Syncing files to device macOS...                                    17ms

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h List all available interactive commands.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).

A Dart VM Service on macOS is available at: http://127.0.0.1:55084/0hJlirxCf38=/
The Flutter DevTools debugger and profiler on macOS is available at:
http://127.0.0.1:55084/0hJlirxCf38=/devtools/?uri=ws://127.0.0.1:55084/0hJlirxCf
38=/ws

══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown while notifying status listeners for AnimationController:
The provided ScrollController is attached to more than one ScrollPosition.
The Scrollbar requires a single ScrollPosition in order to be painted.
When the scrollbar is interactive, the associated ScrollController must only have one ScrollPosition
attached.
The provided ScrollController cannot be shared by multiple ScrollView widgets.

When the exception was thrown, this was the stack:
#0      RawScrollbarState._debugCheckHasValidScrollPosition.<anonymous closure>
(package:flutter/src/widgets/scrollbar.dart:1530:9)
#1      RawScrollbarState._debugCheckHasValidScrollPosition
(package:flutter/src/widgets/scrollbar.dart:1558:6)
#2      RawScrollbarState._validateInteractions (package:flutter/src/widgets/scrollbar.dart:1467:14)
#3      AnimationLocalStatusListenersMixin.notifyStatusListeners
(package:flutter/src/animation/listener_helpers.dart:242:19)
#4      AnimationController._checkStatusChanged
(package:flutter/src/animation/animation_controller.dart:937:7)
#5      AnimationController._tick (package:flutter/src/animation/animation_controller.dart:954:5)
#6      Ticker._tick (package:flutter/src/scheduler/ticker.dart:277:12)
#7      SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1430:15)
#8      SchedulerBinding.handleBeginFrame.<anonymous closure>
(package:flutter/src/scheduler/binding.dart:1263:11)
#9      _LinkedHashMapMixin.forEach (dart:_compact_hash:772:13)
#10     SchedulerBinding.handleBeginFrame (package:flutter/src/scheduler/binding.dart:1261:17)
#11     SchedulerBinding._handleBeginFrame (package:flutter/src/scheduler/binding.dart:1177:5)
#12     _invoke1 (dart:ui/hooks.dart:439:13)
#13     PlatformDispatcher._beginFrame (dart:ui/platform_dispatcher.dart:429:5)
#14     _beginFrame (dart:ui/hooks.dart:384:31)

The AnimationController notifying status listeners was:
  AnimationController#1a61d(⏭ 1.000; paused)
════════════════════════════════════════════════════════════════════════════════════════════════════

Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.

Flutter Doctor output

Doctor output
[✓] Flutter (Channel main, 3.42.0-1.0.pre-341, on macOS 26.3 25D125 darwin-arm64, locale en-US) [2.8s]
    • Flutter version 3.42.0-1.0.pre-341 on channel main at /Users/<user>/dev/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision abffac30ae (2 days ago), 2026-03-01 11:40:35 -0500
    • Engine revision abffac30ae
    • Dart version 3.12.0 (build 3.12.0-198.0.dev)
    • DevTools version 2.55.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-native-assets, omit-legacy-version-file, enable-lldb-debugging, enable-uiscene-migration, enable-riscv64

[✗] Android toolchain - develop for Android devices [536ms]
    ✗ Unable to locate Android SDK.
      Install Android Studio from: https://developer.android.com/studio/index.html
      On first launch it will assist you in installing the Android SDK components.
      (or visit https://flutter.dev/to/macos-android-setup for detailed instructions).
      If the Android SDK has been installed to a custom location, please use
      `flutter config --android-sdk` to update to that location.


[!] Xcode - develop for iOS and macOS (Xcode 16.2) [2.1s]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 16C5032a
    ✗ Unable to get list of installed Simulator runtimes.
    • CocoaPods version 1.16.2

[✓] Chrome - develop for the web [6ms]
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Connected device (2 available) [5.8s]
    • macOS (desktop) • macos  • darwin-arm64   • macOS 26.3 25D125 darwin-arm64
    • Chrome (web)    • chrome • web-javascript • Google Chrome 145.0.7632.119

[✓] Network resources [209ms]
    • All expected network resources are available.

! Doctor found issues in 2 categories.

Activity

  1. saurabh-mirajkar commented on Mar 4, 2026

    @saurabh-mirajkar
    Contributor

    @treeplate Thanks for the detailed reproduction steps - this reproduces using the official NestedScrollView sample on macOS with specific trackpad gesture interactions. Labeling for triage.

    Video Demonstration

    video-demo.mov

    Log Output

    ══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
    The following assertion was thrown while notifying status listeners for AnimationController:
    The provided ScrollController is attached to more than one ScrollPosition.
    The Scrollbar requires a single ScrollPosition in order to be painted.
    When the scrollbar is interactive, the associated ScrollController must only have one ScrollPosition
    attached.
    The provided ScrollController cannot be shared by multiple ScrollView widgets.
    
    When the exception was thrown, this was the stack:
    #0      RawScrollbarState._debugCheckHasValidScrollPosition.<anonymous closure> (package:flutter/src/widgets/scrollbar.dart:1530:9)
    #1      RawScrollbarState._debugCheckHasValidScrollPosition (package:flutter/src/widgets/scrollbar.dart:1558:6)
    #2      RawScrollbarState._validateInteractions (package:flutter/src/widgets/scrollbar.dart:1467:14)
    #3      AnimationLocalStatusListenersMixin.notifyStatusListeners (package:flutter/src/animation/listener_helpers.dart:242:19)
    #4      AnimationController._checkStatusChanged (package:flutter/src/animation/animation_controller.dart:937:7)
    #5      AnimationController._startSimulation (package:flutter/src/animation/animation_controller.dart:870:5)
    #6      AnimationController._animateToInternal (package:flutter/src/animation/animation_controller.dart:687:12)
    #7      AnimationController.reverse (package:flutter/src/animation/animation_controller.dart:521:12)
    #8      RawScrollbarState._maybeStartFadeoutTimer.<anonymous closure> (package:flutter/src/widgets/scrollbar.dart:1611:37)
    #12     _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)
    (elided 3 frames from class _Timer and dart:async-patch)
    
    The AnimationController notifying status listeners was:
      AnimationController#2c835(◀ 1.000)
    ════════════════════════════════════════════════════════════════════════════════════════════════════
    
    Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.
    Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.
    Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.
    Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.
    Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.
    Another exception was thrown: The provided ScrollController is attached to more than one ScrollPosition.
    

    Doctor Output

    1. Main channel
    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel main, 3.42.0-1.0.pre-381, on macOS 26.3 25D125 darwin-arm64, locale en-US)
    [✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
    [✓] Xcode - develop for iOS and macOS (Xcode 26.2)
    [✓] Chrome - develop for the web
    [✓] Connected device (2 available)
    [✓] Network resources
    
    • No issues found!
    
    1. Stable channel
    Doctor summary (to see all details, run flutter doctor -v):
    [✓] Flutter (Channel stable, 3.41.3, on macOS 26.3 25D125 darwin-arm64, locale en-US)
    [✓] Android toolchain - develop for Android devices (Android SDK version 36.1.0)
    [✓] Xcode - develop for iOS and macOS (Xcode 26.2)
    [✓] Chrome - develop for the web
    [✓] Connected device (2 available)
    [✓] Network resources
    
    • No issues found!
    
  2. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    platform-macosBuilding on or for macOS specifically
    f: scrollingViewports, list views, slivers, etc.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    and removed
    in triagePresently being triaged by the triage team
    on Mar 4, 2026
  3. added
    P2Important issues not at the top of the work list
    on Mar 10, 2026
  4. justinmc commented on Mar 10, 2026

    @justinmc
    Contributor

    Does anyone know if this happens on other platforms or just Mac?

  5. maRci002 commented on Mar 11, 2026

    @maRci002
    Contributor

    The real problem seems to be the error message: "The provided ScrollController cannot be shared by multiple ScrollView widgets."
    I believe the underlying issue may be #159123.

    My guess is that the exception is triggered when Scrollbar tries to paint itself. The Scrollbar requires a single ScrollPosition from the ScrollController in order to determine the scroll offset and paint correctly. However, in this situation the ScrollController already has multiple ScrollPositions attached, which causes the assertion.

    On mobile, where a Scrollbar is typically not used by default, the issue may not surface.

  6. github-actions commented on Aug 12, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  7. locked as resolved and limited conversation to collaborators on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listf: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-macosBuilding on or for macOS specificallyteam-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions