Skip to content

CarouselView: using PageStorageKey throws Null check operator used on a null value #166067

@danielwinkler

Description

@danielwinkler

Steps to reproduce

I have a CarouselView in a NestedScrollView with a CustomScrollView, see the minimal code sample below.

The key: const PageStorageKey<String>("ooopsie"), is causing the applyViewportDimension method in _CarouselPosition to throw an null check operator used on a null value.

This comes from the fact, that the logic

  @override
  bool applyViewportDimension(double viewportDimension) {
    final double? oldViewportDimensions = hasViewportDimension ? this.viewportDimension : null;
    if (viewportDimension == oldViewportDimensions) {
      return true;
    }
    final bool result = super.applyViewportDimension(viewportDimension);
    final double? oldPixels = hasPixels ? pixels : null;
    double item;
    if (oldPixels == null) {
      item = updateLeadingItem(flexWeights, consumeMaxWeight);
    } else if (oldViewportDimensions == 0.0) {
      // If resize from zero, we should use the _cachedItem to recover the state.
      item = _cachedItem!;
    } else {
      item = getItemFromPixels(oldPixels, oldViewportDimensions!);
    }
    final double newPixels = getPixelsFromItem(item, flexWeights, itemExtent);
    // If the viewportDimension is zero, cache the item
    // in case the viewport is resized to be non-zero.
    _cachedItem = (viewportDimension == 0.0) ? item : null;

    if (newPixels != oldPixels) {
      correctPixels(newPixels);
      return false;
    }
    return result;
  }

is making assumptions on the state of the position that aren't correct.

Please note that this code is also in page_view.dart / _PagePosition.

Expected results

The carousel should be rendered.

Actual results

An error is reported and the CarouselView is not rendered.

Code sample

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: NestedScrollView(
          floatHeaderSlivers: true,
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                title: const Text('Header'),
                floating: true,
                expandedHeight: 120.0,
                forceElevated: innerBoxIsScrolled,
              ),
            ];
          },

          body: const CarouselExample(),
        ),
      ),
    );
  }
}

class CarouselExample extends StatefulWidget {
  const CarouselExample({super.key});

  @override
  State<CarouselExample> createState() => _CarouselExampleState();
}

class _CarouselExampleState extends State<CarouselExample> {
  final CarouselController controller = CarouselController(initialItem: 2);

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      key: const PageStorageKey<String>("ooopsie"),
      slivers: [
        SliverToBoxAdapter(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxHeight: 50),
            child: CarouselView.weighted(
              flexWeights: const <int>[1, 2],
              consumeMaxWeight: false,
              children: List<Widget>.generate(20, (int index) {
                return ColoredBox(
                  color: Colors.primaries[index % Colors.primaries.length].withValues(alpha: 0.8),
                  child: const SizedBox.expand(),
                );
              }),
            ),
          ),
        ),
      ],
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
Restarted application in 249ms.

════════ Exception caught by rendering library ═════════════════════════════════
The following _TypeError was thrown during performLayout():
Null check operator used on a null value

The relevant error-causing widget was:
    CarouselView CarouselView:file:///xxx/fluttercarouselview/lib/main.dart:58:33

When the exception was thrown, this was the stack:
#0      _CarouselPosition.applyViewportDimension (package:flutter/src/material/carousel.dart:1473:64)
carousel.dart:1473
#1      RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1443:16)
viewport.dart:1443
#2      RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#3      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#4      RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#5      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#6      RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#7      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#8      RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#9      RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#10     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#11     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#12     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#13     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#14     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#15     _RenderLayoutBuilder.performLayout (package:flutter/src/widgets/layout_builder.dart:392:14)
layout_builder.dart:392
#16     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#17     RenderConstrainedBox.performLayout (package:flutter/src/rendering/proxy_box.dart:293:14)
proxy_box.dart:293
#18     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#19     RenderSliverToBoxAdapter.performLayout (package:flutter/src/rendering/sliver.dart:2020:12)
sliver.dart:2020
#20     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#21     RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:608:13)
viewport.dart:608
#22     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1576:12)
viewport.dart:1576
#23     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1467:20)
viewport.dart:1467
#24     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#25     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#26     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#27     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#28     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#29     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#30     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#31     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#32     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#33     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#34     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#35     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#36     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#37     RenderSliverFillRemainingWithScrollable.performLayout (package:flutter/src/rendering/sliver_fill.dart:103:14)
sliver_fill.dart:103
#38     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#39     RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:608:13)
viewport.dart:608
#40     RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1576:12)
viewport.dart:1576
#41     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1467:20)
viewport.dart:1467
#42     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#43     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#44     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#45     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#46     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#47     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#48     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#49     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#50     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#51     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#52     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#53     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#54     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#55     MultiChildLayoutDelegate.layoutChild (package:flutter/src/rendering/custom_layout.dart:180:12)
custom_layout.dart:180
#56     _ScaffoldLayout.performLayout (package:flutter/src/material/scaffold.dart:1118:7)
scaffold.dart:1118
#57     MultiChildLayoutDelegate._callPerformLayout (package:flutter/src/rendering/custom_layout.dart:249:7)
custom_layout.dart:249
#58     RenderCustomMultiChildLayoutBox.performLayout (package:flutter/src/rendering/custom_layout.dart:419:14)
custom_layout.dart:419
#59     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#60     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#61     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#62     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#63     _RenderCustomClip.performLayout (package:flutter/src/rendering/proxy_box.dart:1483:11)
proxy_box.dart:1483
#64     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#65     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#66     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#67     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#68     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#69     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#70     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#71     ChildLayoutHelper.layoutChild (package:flutter/src/rendering/layout_helper.dart:62:11)
layout_helper.dart:62
#72     RenderStack._computeSize (package:flutter/src/rendering/stack.dart:646:43)
stack.dart:646
#73     RenderStack.performLayout (package:flutter/src/rendering/stack.dart:673:12)
stack.dart:673
#74     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#75     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#76     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#77     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#78     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#79     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#80     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#81     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#82     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#83     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#84     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#85     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#86     RenderOffstage.performLayout (package:flutter/src/rendering/proxy_box.dart:3750:13)
proxy_box.dart:3750
#87     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#88     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#89     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#90     _RenderTheaterMixin.layoutChild (package:flutter/src/widgets/overlay.dart:1076:13)
overlay.dart:1076
#91     _RenderTheater.performLayout (package:flutter/src/widgets/overlay.dart:1422:9)
overlay.dart:1422
#92     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#93     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#94     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#95     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#96     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#97     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#98     RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#99     RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#100    RenderCustomPaint.performLayout (package:flutter/src/rendering/custom_paint.dart:574:11)
custom_paint.dart:574
#101    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#102    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#103    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#104    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#105    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#106    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#107    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#108    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#109    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#110    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#111    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#112    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#113    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#114    RenderProxyBoxMixin.performLayout (package:flutter/src/rendering/proxy_box.dart:115:18)
proxy_box.dart:115
#115    RenderObject.layout (package:flutter/src/rendering/object.dart:2715:7)
object.dart:2715
#116    RenderView.performLayout (package:flutter/src/rendering/view.dart:294:12)
view.dart:294
#117    RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:2548:7)
object.dart:2548
#118    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1112:18)
object.dart:1112
#119    PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:1125:15)
object.dart:1125
#120    RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:616:23)
binding.dart:616
#121    WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:1231:13)
binding.dart:1231
#122    RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:482:5)
binding.dart:482
#123    SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1442:15)
binding.dart:1442
#124    SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1355:9)
binding.dart:1355
#125    SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:1064:9)
binding.dart:1064
#126    PlatformDispatcher.scheduleWarmUpFrame.<anonymous closure> (dart:ui/platform_dispatcher.dart:873:16)
platform_dispatcher.dart:873
#130    _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:194:12)
isolate_patch.dart:194
(elided 3 frames from class _Timer and dart:async-patch)

The following RenderObject was being processed when the exception was fired: RenderViewport#c67bd NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
    needs compositing
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=402.0, 0.0<=h<=50.0)
    size: Size(402.0, 50.0)
    axisDirection: right
    crossAxisDirection: down
    offset: _CarouselPosition#f721d(offset: 0.0, range: null..null, viewport: 402.0, ScrollableState, BouncingScrollPhysics -> RangeMaintainingScrollPhysics -> BouncingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#bea40, ScrollDirection.idle)
    anchor: 0.0
    center child: _RenderSliverWeightedCarousel#bd5db NEEDS-LAYOUT NEEDS-PAINT
        parentData: paintOffset=Offset(0.0, 0.0)
        constraints: MISSING
        geometry: null
        no children current live
RenderObject: RenderViewport#c67bd NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
    needs compositing
    parentData: <none> (can use size)
    constraints: BoxConstraints(w=402.0, 0.0<=h<=50.0)
    size: Size(402.0, 50.0)
    axisDirection: right
    crossAxisDirection: down
    offset: _CarouselPosition#f721d(offset: 0.0, range: null..null, viewport: 402.0, ScrollableState, BouncingScrollPhysics -> RangeMaintainingScrollPhysics -> BouncingScrollPhysics -> RangeMaintainingScrollPhysics, IdleScrollActivity#bea40, ScrollDirection.idle)
    anchor: 0.0
    center child: _RenderSliverWeightedCarousel#bd5db NEEDS-LAYOUT NEEDS-PAINT
        parentData: paintOffset=Offset(0.0, 0.0)
        constraints: MISSING
        geometry: null
        no children current live
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by rendering library ═════════════════════════════════
Null check operator used on a null value
The relevant error-causing widget was:
    CarouselView CarouselView:file:///xxx/fluttercarouselview/lib/main.dart:58:33
The following RenderObject was being processed when the exception was fired: RenderViewport#c67bd
RenderObject: RenderViewport#c67bd
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by scheduler library ═════════════════════════════════
Null check operator used on a null value
════════════════════════════════════════════════════════════════════════════════

════════ Exception caught by Flutter framework ═════════════════════════════════
'package:flutter/src/widgets/binding.dart': Failed assertion: line 1207 pos 16: 'debugFrameWasSentToEngine': is not true.
════════════════════════════════════════════════════════════════════════════════

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.29.0, on macOS 15.3.1 24D70 darwin-arm64, locale en-US)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.1)
[✓] Xcode - develop for iOS and macOS (Xcode 16.0)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.2)
[✓] VS Code (version 1.98.2)
[✓] Connected device (4 available)
    ! Error: Browsing on the local area network for Felix Stotz’s iPad. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
    ! Error: Browsing on the local area network for Felix Stotz’s iPhone. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)
[✓] Network resources

• No issues found!

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work listf: material designflutter/packages/flutter/material repository.found in release: 3.29Found to occur in 3.29found in release: 3.31Found to occur in 3.31frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onr: fixedIssue is closed as already fixed in a newer versionteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

Type

No type

Projects

Status

Done (PR merged)

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions