Removing children from a ListView that has a zero-height child with a Key throws Exception

Steps to Reproduce

  1. run main.dart:
import 'package:flutter/material.dart';

void main() => runApp(MaterialApp(home: Scaffold(body: Test())));

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
  bool showing = true;

  @override
  Widget build(BuildContext context) {
    return ListView(children: [
      if (showing)
        for (int i = 0; i < 20; i++)
          Container(
            height: 100,
            child: const Placeholder(),
          ),
      Container(
        height: 400,
        alignment: Alignment.bottomCenter,
        color: Colors.red,
        child: RaisedButton(
          onPressed: () => setState(() => showing = !showing),
          child: Text(showing ? 'hide' : 'show'),
        ),
      ),
      // a zero-sized widget with a key will cause an exception
      // to be thrown when the user clicks "hide"
      const SizedBox.shrink(key: Key('break')),
    ]);
  }
}
  1. Scroll down and click the button

Expected results:

These placeholder items should disappear and no exceptions should be thrown.

Actual results:

This exceptions is thrown:

Exception
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performLayout():
flutter: 'package:flutter/src/rendering/sliver_multi_box_adaptor.dart': Failed assertion: line 580 pos 12:
flutter: 'child != null': is not true.
flutter:
flutter: Either the assertion indicates an error in the framework itself, or we should provide substantially
flutter: more information in this error message to help you determine and fix the underlying cause.
flutter: In either case, please report this assertion by filing a bug on GitHub:
flutter:   https://github.com/flutter/flutter/issues/new?template=BUG.md
flutter:
flutter: The relevant error-causing widget was:
flutter:   ListView file:///Users/kami/development/sliver_list_test/lib/main.dart:15:12
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #2      RenderSliverMultiBoxAdaptor.childScrollOffset (package:flutter/src/rendering/sliver_multi_box_adaptor.dart:580:12)
flutter: #3      RenderSliverList.performLayout (package:flutter/src/rendering/sliver_list.dart:106:14)
flutter: #4      RenderObject.layout (package:flutter/src/rendering/object.dart:1769:7)
flutter: #5      RenderSliverEdgeInsetsPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:137:11)
flutter: #6      RenderSliverPadding.performLayout (package:flutter/src/rendering/sliver_padding.dart:377:11)
flutter: #7      RenderObject.layout (package:flutter/src/rendering/object.dart:1769:7)
flutter: #8      RenderViewportBase.layoutChildSequence (package:flutter/src/rendering/viewport.dart:471:13)
flutter: #9      RenderViewport._attemptLayout (package:flutter/src/rendering/viewport.dart:1465:12)
flutter: #10     RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1374:20)
flutter: #11     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1632:7)
flutter: #12     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:889:18)
flutter: #13     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:404:19)
flutter: #14     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:867:13)
flutter: #15     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:286:5)
flutter: #16     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
flutter: #17     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1056:9)
flutter: #18     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:972:5)
flutter: #22     _invoke (dart:ui/hooks.dart:253:10)
flutter: #23     _drawFrame (dart:ui/hooks.dart:211:3)
flutter: (elided 5 frames from class _AssertionError and dart:async)
flutter:
flutter: The following RenderObject was being processed when the exception was fired: RenderSliverList#9928a relayoutBoundary=up2 NEEDS-LAYOUT NEEDS-COMPOSITING-BITS-UPDATE:
flutter:   needs compositing
flutter:   creator: SliverList ← MediaQuery ← SliverPadding ← Viewport ← IgnorePointer-[GlobalKey#42b87] ←
flutter:     Semantics ← _PointerListener ← Listener ← _GestureSemantics ←
flutter:     RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#9a69b] ← _PointerListener ← Listener
flutter:     ← ⋯
flutter:   parentData: paintOffset=Offset(0.0, 0.0) (can use size)
flutter:   constraints: SliverConstraints(AxisDirection.down, GrowthDirection.forward, ScrollDirection.idle,
flutter:     scrollOffset: 433.0, remainingPaintExtent: 667.0, crossAxisExtent: 375.0, crossAxisDirection:
flutter:     AxisDirection.right, viewportMainAxisExtent: 667.0, remainingCacheExtent: 1167.0, cacheOrigin:
flutter:     -230.0)
flutter:   geometry: SliverGeometry(scrollExtent: 1100.0, paintExtent: 667.0, maxPaintExtent: 1100.0,
flutter:     hasVisualOverflow: true, cacheExtent: 897.0)
flutter:   currently live children: 1 to 1
flutter: This RenderObject had the following descendants (showing up to depth 5):
flutter:     child with index 1: RenderIndexedSemantics#605d2 relayoutBoundary=up3
flutter:       child: RenderRepaintBoundary#3f1b0 relayoutBoundary=up4
flutter:         child: RenderConstrainedBox#6e57a relayoutBoundary=up5
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: Another exception was thrown: NoSuchMethodError: The method '-' was called on null.
flutter: Another exception was thrown: NoSuchMethodError: The method '-' was called on null.
flutter analyze
Analyzing lib...
No issues found! (ran in 1.6s)

This happens on all current versions of Flutter, from stable to master (with slightly different exceptions due to NNBD).
Here’s my doctor output from stable:

flutter doctor -v
Downloading android-arm-profile/darwin-x64 tools...                 1.5s
Downloading android-arm-release/darwin-x64 tools...                 1.0s
Downloading android-arm64-profile/darwin-x64 tools...               1.4s
Downloading android-arm64-release/darwin-x64 tools...               1.3s
Downloading android-x64-profile/darwin-x64 tools...                 1.4s
Downloading android-x64-release/darwin-x64 tools...                 1.4s
[✓] Flutter (Channel stable, 1.20.4, on Mac OS X 10.15.6 19G73, locale en-GB)
    • Flutter version 1.20.4 at /Users/kami/development/flutter
    • Framework revision fba99f6cf9 (5 days ago), 2020-09-14 15:32:52 -0700
    • Engine revision d1bc06f032
    • Dart version 2.9.2


[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
    • Android SDK at /Users/kami/Library/Android/sdk
    • Platform android-29, build-tools 29.0.2
    • ANDROID_HOME = /Users/kami/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.6)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.6, Build version 11E708
    • CocoaPods version 1.8.4

[✓] Android Studio (version 4.0)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 49.0.2
    • Dart plugin version 193.7547
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[!] IntelliJ IDEA Ultimate Edition (version 2019.1.2)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • For information about installing plugins, see
      https://flutter.dev/intellij-setup/#installing-the-plugins

[✓] VS Code (version 1.48.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.13.2

[✓] Connected device (1 available)
    • iPhone SE (2nd generation) (mobile) • 82B6CB8E-818C-4556-A5FB-087F35387B7B • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-6 (simulator)

! Doctor found issues in 1 category.

Removing the key from the SizedBox.shrink() widget will stop the exception from being thrown, as does removing the SizedBox.shrink() widget altogether.

Thanks to @Kavantix for helping me to create a reproducible version of this issue.

I stumbled upon this while adding a new feature to my app, and this manifested itself in the app completely locking up without throwing an exception, also hot-reload and hot-restart stopped working, it was like Flutter was stuck in an endless loop or something.

I’m not able to reproduce this behaviour (of completely locking up) outside of my app, though.

1 possible answer(s) on “Removing children from a ListView that has a zero-height child with a Key throws Exception