Skip to content

Exception is thrown when scrolling a bottom sheet with mouse wheel or mouse drag #374

@rydmikework

Description

@rydmikework

Bug report

When you scroll a Wolt Modal bottom sheet with a mouse scroll wheel or by holding down the mouse and dragging, an exception is thrown by Flutter SDK.

════════ Exception caught by gestures library ══════════════════════════════════
'package:flutter/src/rendering/proxy_box.dart': Failed assertion: line 2948 pos 12: '!debugNeedsLayout': is not true.

Steps to reproduce

Use the short code sample given further below to reproduce the error. (The error can also be seen with the package own sample).

  • Used package version: 0.11.0
  • Used Flutter version: 3.29.3

Build a macOS desktop app.

Press "Open test sheet".

Scroll the bottom sheet content with a mouse scroll wheel.

OR

If you have mouse drag scrolling enabled, like in this example, you can also trigger the error by holding down the mouse button on the scrolling content and dragging the content up and down.

Expected behavior

Expect the content to scroll without issues.

Actual behavior

The app throws the exception shown in video and log below.

If you scroll with the trackpad the exception is typically not thrown, although you can get it occasionally then also if you scroll really fast back and forth with the trackpad. Often also when you drag-close the sheet with the trackpad.

Video demo

Screen.Recording.2025-04-26.at.22.52.19.mov

Exception log

======== Exception caught by gestures library ======================================================
The following assertion was thrown while handling a pointer data packet:
'package:flutter/src/rendering/proxy_box.dart': Failed assertion: line 2948 pos 12: '!debugNeedsLayout': is not true.


Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
  https://github.com/flutter/flutter/issues/new?template=2_bug.yml

When the exception was thrown, this was the stack: 
#2      RenderFractionalTranslation.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:2948:12)
#3      RenderFractionalTranslation.hitTest (package:flutter/src/rendering/proxy_box.dart:2935:12)
#4      RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#5      RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#6      RenderShiftedBox.hitTestChildren.<anonymous closure> (package:flutter/src/rendering/shifted_box.dart:95:24)
#7      BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#8      RenderShiftedBox.hitTestChildren (package:flutter/src/rendering/shifted_box.dart:90:21)
#9      RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#10     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#11     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#12     RenderClipRect.hitTest (package:flutter/src/rendering/proxy_box.dart:1568:18)
#13     RenderBoxContainerDefaultsMixin.defaultHitTestChildren.<anonymous closure> (package:flutter/src/rendering/box.dart:3339:25)
#14     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#15     RenderBoxContainerDefaultsMixin.defaultHitTestChildren (package:flutter/src/rendering/box.dart:3334:33)
#16     RenderStack.hitTestChildren (package:flutter/src/rendering/stack.dart:695:12)
#17     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#18     RenderBoxContainerDefaultsMixin.defaultHitTestChildren.<anonymous closure> (package:flutter/src/rendering/box.dart:3339:25)
#19     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#20     RenderBoxContainerDefaultsMixin.defaultHitTestChildren (package:flutter/src/rendering/box.dart:3334:33)
#21     RenderStack.hitTestChildren (package:flutter/src/rendering/stack.dart:695:12)
#22     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#23     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#24     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#25     RenderAbsorbPointer.hitTest (package:flutter/src/rendering/proxy_box.dart:3877:56)
#26     RenderShiftedBox.hitTestChildren.<anonymous closure> (package:flutter/src/rendering/shifted_box.dart:95:24)
#27     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#28     RenderShiftedBox.hitTestChildren (package:flutter/src/rendering/shifted_box.dart:90:21)
#29     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#30     _RenderLayoutBuilder.hitTestChildren (package:flutter/src/widgets/layout_builder.dart:407:19)
#31     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#32     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#33     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#34     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#35     RenderCustomPaint.hitTestChildren (package:flutter/src/rendering/custom_paint.dart:564:18)
#36     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#37     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#38     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#39     RenderPhysicalShape.hitTest (package:flutter/src/rendering/proxy_box.dart:2138:18)
#40     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#41     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#42     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#43     RenderProxyBoxWithHitTestBehavior.hitTest (package:flutter/src/rendering/proxy_box.dart:183:19)
#44     RenderBoxContainerDefaultsMixin.defaultHitTestChildren.<anonymous closure> (package:flutter/src/rendering/box.dart:3339:25)
#45     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#46     RenderBoxContainerDefaultsMixin.defaultHitTestChildren (package:flutter/src/rendering/box.dart:3334:33)
#47     RenderCustomMultiChildLayoutBox.hitTestChildren (package:flutter/src/rendering/custom_layout.dart:429:12)
#48     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#49     RenderShiftedBox.hitTestChildren.<anonymous closure> (package:flutter/src/rendering/shifted_box.dart:95:24)
#50     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#51     RenderShiftedBox.hitTestChildren (package:flutter/src/rendering/shifted_box.dart:90:21)
#52     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#53     RenderBoxContainerDefaultsMixin.defaultHitTestChildren.<anonymous closure> (package:flutter/src/rendering/box.dart:3339:25)
#54     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#55     RenderBoxContainerDefaultsMixin.defaultHitTestChildren (package:flutter/src/rendering/box.dart:3334:33)
#56     RenderCustomMultiChildLayoutBox.hitTestChildren (package:flutter/src/rendering/custom_layout.dart:429:12)
#57     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#58     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#59     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#60     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#61     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#62     RenderPhysicalModel.hitTest (package:flutter/src/rendering/proxy_box.dart:2032:18)
#63     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#64     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#65     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#66     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#67     RenderIgnorePointer.hitTest (package:flutter/src/rendering/proxy_box.dart:3625:31)
#68     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#69     RenderFractionalTranslation.hitTestChildren.<anonymous closure> (package:flutter/src/rendering/proxy_box.dart:2956:22)
#70     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#71     RenderFractionalTranslation.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:2949:19)
#72     RenderFractionalTranslation.hitTest (package:flutter/src/rendering/proxy_box.dart:2935:12)
#73     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#74     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#75     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#76     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#77     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#78     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#79     RenderOffstage.hitTest (package:flutter/src/rendering/proxy_box.dart:3756:31)
#80     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#81     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#82     _RenderTheaterMixin.hitTestChildren.childHitTest (package:flutter/src/widgets/overlay.dart:1097:22)
#83     BoxHitTestResult.addWithPaintOffset (package:flutter/src/rendering/box.dart:840:31)
#84     _RenderTheaterMixin.hitTestChildren (package:flutter/src/widgets/overlay.dart:1098:22)
#85     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#86     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#87     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#88     RenderAbsorbPointer.hitTest (package:flutter/src/rendering/proxy_box.dart:3877:56)
#89     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#90     RenderProxyBoxWithHitTestBehavior.hitTest (package:flutter/src/rendering/proxy_box.dart:183:19)
#91     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#92     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#93     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#94     RenderCustomPaint.hitTestChildren (package:flutter/src/rendering/custom_paint.dart:564:18)
#95     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#96     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#97     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#98     RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#99     RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#100    RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#101    RenderTapRegionSurface.hitTest (package:flutter/src/widgets/tap_region.dart:234:28)
#102    RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#103    RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#104    RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#105    RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#106    RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#107    RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#108    RenderProxyBoxMixin.hitTestChildren (package:flutter/src/rendering/proxy_box.dart:128:19)
#109    RenderBox.hitTest (package:flutter/src/rendering/box.dart:2943:11)
#110    RenderView.hitTest (package:flutter/src/rendering/view.dart:311:12)
#111    RendererBinding.hitTestInView (package:flutter/src/rendering/binding.dart:649:34)
#112    GestureBinding._handlePointerEventImmediately (package:flutter/src/gestures/binding.dart:408:7)
#113    GestureBinding.handlePointerEvent (package:flutter/src/gestures/binding.dart:394:5)
#114    GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:341:7)
#115    GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:308:9)
#116    _invoke1 (dart:ui/hooks.dart:332:13)
#117    PlatformDispatcher._dispatchPointerDataPacket (dart:ui/platform_dispatcher.dart:451:7)
#118    _dispatchPointerDataPacket (dart:ui/hooks.dart:267:31)
(elided 2 frames from class _AssertionError)

Code sample

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Wolt Modal Sheet Issue',
      scrollBehavior: DragScrollBehavior(),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Wolt Modal Sheet Issue')),
      body: Center(
        child: ElevatedButton(
          child: const Text('Open test sheet'),
          onPressed: () {
            WoltModalSheet.show<void>(
              context: context,
              pageListBuilder: (modalSheetContext) {
                return [_buildPage(modalSheetContext)];
              },
              modalTypeBuilder: (context) {
                return WoltBottomSheetType();
              },
              onModalDismissedWithDrag: () {
                debugPrint('Bottom sheet is dismissed with drag.');
                Navigator.of(context).pop();
              },
              onModalDismissedWithBarrierTap: () {
                debugPrint('Modal is dismissed with barrier tap.');
                Navigator.of(context).pop();
              },
            );
          },
        ),
      ),
    );
  }

  SliverWoltModalSheetPage _buildPage(BuildContext modalSheetContext) {
    return WoltModalSheetPage(
      hasSabGradient: false, // Remove default gradient overlay
      topBarTitle: const Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(
          'Demo of scroll issue',
          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
        ),
      ),
      isTopBarLayerAlwaysVisible: true, // Keep title visible when scrolling
      // Main content is the scrollable list
      child: ListView.builder(
        physics: const ClampingScrollPhysics(),
        shrinkWrap: true,
        itemCount: 50,
        itemBuilder: (BuildContext context, int index) {
          return ListTile(
            title: Text('Scrolling content ${index + 1}'),
            leading: CircleAvatar(child: Text('${index + 1}')),
          );
        },
      ),
    );
  }
}

// Define a custom scroll behavior that enables mouse dragging
class DragScrollBehavior extends MaterialScrollBehavior {
  // Override behavior methods and getters like dragDevices
  @override
  Set<PointerDeviceKind> get dragDevices => {
    PointerDeviceKind.touch,
    PointerDeviceKind.trackpad,
    PointerDeviceKind.stylus,
    PointerDeviceKind.invertedStylus,
    PointerDeviceKind.mouse,
  };
}

Blocker issue at HypeHype for adopting Wolt Modal Sheet

We are trying Wolt modal sheet at HypeHype, but since our app for devs in debug mode shows exceptions also on purpose to the dev in annoying popup's in the app during development, it pretty much makes the package a no starter as it spams the entire app with error popups all the time when you scroll on desktop build.

The HypeHype game platform app supports and targets iOS, Android, Windows, macOS and Web.

This is an example of what it looks like when we use it:

hh_demo.mov

Clearly not a very nice dev experience.


Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions