Skip to content

" '_children[j] is MaterialGap': is not true " when updating state of ExpansionPanelList #128646

@Snonky

Description

@Snonky

Is there an existing issue for this?

Steps to reproduce

Even though #13780 has been thoroughly discussed, I am still experiencing a crash when adding/removing ExpansionPanels to an ExpansionPanelList.

To reproduce in the minimal working example:

  1. Expand Panel 1 so you see "This is item number 1"
  2. Click the buttons 1, 2 & 3 in order

Expected results

Button 1 removes the first 2 list entries.
Button 2 adds them back and Panel 1 retains its expanded state.
Button 3 removes the last list entry.

Actual results

Button 3 causes an assertion error '_children[j] is MaterialGap': is not true

Code sample

The error can be reproduced using both ExpansionPanelList and ExpansionPanelList.radio

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

/// Flutter code sample for [ExpansionPanelList].

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ExpansionPanelList Sample')),
        body: const ExpansionPanelListExample(),
      ),
    );
  }
}

// stores ExpansionPanel state information
class Item {
  Item({
    required this.expandedValue,
    required this.headerValue,
  });

  String expandedValue;
  String headerValue;
}

List<Item> generateAllPanels() {
  return List<Item>.generate(3, (int index) {
    return Item(
      headerValue: 'Panel $index',
      expandedValue: 'This is item number $index',
    );
  });
}

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

  @override
  State<ExpansionPanelListExample> createState() =>
      _ExpansionPanelListExampleState();
}

class _ExpansionPanelListExampleState extends State<ExpansionPanelListExample> {
  final List<Item> _data = generateAllPanels();
  List<String> expandedPanels = [];

  void removePanel0_1() {
    _data.removeRange(0, 2);
  }

  void readdPanel0_1() {
    _data.insert(
      0,
      Item(
        headerValue: 'Panel 1',
        expandedValue: 'This is item number 1',
      ),
    );
    _data.insert(
      0,
      Item(
        headerValue: 'Panel 0',
        expandedValue: 'This is item number 0',
      ),
    );
  }

  void removePanel2() {
    _data.removeLast();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Container(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                setState(() {
                  removePanel0_1();
                });
              },
              child: const Text('Button 1 (removes panel 0+1)'),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  readdPanel0_1();
                });
              },
              child: const Text('Button 2 (re-adds panel 0+1)'),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  removePanel2();
                });
              },
              child: const Text('Button 3 (removes panel 2)'),
            ),
            _buildPanel(),
          ],
        ),
      ),
    );
  }

  Widget _buildPanel() {
    return ExpansionPanelList(
      expansionCallback: (int index, bool isExpanded) {
        setState(() {
          if (expandedPanels.contains(_data[index].headerValue)) {
            expandedPanels.remove(_data[index].headerValue);
          } else {
            expandedPanels.add(_data[index].headerValue);
          }
        });
      },
      children: _data.map<ExpansionPanel>((Item item) {
        return ExpansionPanel(
          canTapOnHeader: true,
          //value: item.headerValue,
          isExpanded: expandedPanels.contains(item.headerValue),
          headerBuilder: (BuildContext context, bool isExpanded) {
            return ListTile(
              title: Text(item.headerValue),
            );
          },
          body: ListTile(
            title: Text(item.expandedValue),
          ),
        );
      }).toList(),
    );
  }
}
Code sample with ExpansionPanelList.radio
import 'package:flutter/material.dart';

/// Flutter code sample for [ExpansionPanelList].

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('ExpansionPanelList Sample')),
        body: const ExpansionPanelListExample(),
      ),
    );
  }
}

// stores ExpansionPanel state information
class Item {
  Item({
    required this.expandedValue,
    required this.headerValue,
  });

  String expandedValue;
  String headerValue;
}

List<Item> generateAllPanels() {
  return List<Item>.generate(3, (int index) {
    return Item(
      headerValue: 'Panel $index',
      expandedValue: 'This is item number $index',
    );
  });
}

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

  @override
  State<ExpansionPanelListExample> createState() =>
      _ExpansionPanelListExampleState();
}

class _ExpansionPanelListExampleState extends State<ExpansionPanelListExample> {
  final List<Item> _data = generateAllPanels();

  void removePanel0_1() {
    _data.removeRange(0, 2);
  }

  void readdPanel0_1() {
    _data.insert(
      0,
      Item(
        headerValue: 'Panel 1',
        expandedValue: 'This is item number 1',
      ),
    );
    _data.insert(
      0,
      Item(
        headerValue: 'Panel 0',
        expandedValue: 'This is item number 0',
      ),
    );
  }

  void removePanel2() {
    _data.removeLast();
  }

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      child: Container(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () {
                setState(() {
                  removePanel0_1();
                });
              },
              child: const Text('Button 1 (removes panel 0+1)'),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  readdPanel0_1();
                });
              },
              child: const Text('Button 2 (re-adds panel 0+1)'),
            ),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  removePanel2();
                });
              },
              child: const Text('Button 3 (removes panel 2)'),
            ),
            _buildPanel(),
          ],
        ),
      ),
    );
  }

  Widget _buildPanel() {
    return ExpansionPanelList.radio(
      children: _data.map<ExpansionPanel>((Item item) {
        return ExpansionPanelRadio(
          canTapOnHeader: true,
          value: item.headerValue,
          headerBuilder: (BuildContext context, bool isExpanded) {
            return ListTile(
              title: Text(item.headerValue),
            );
          },
          body: ListTile(
            title: Text(item.expandedValue),
          ),
        );
      }).toList(),
    );
  }
}

Screenshots or Video

Screenshots / Video demonstration
2023-06-11.03-12-09.mp4

Logs

Assertion error from this line

Logs
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following assertion was thrown building ExpansionPanelList(state:
_ExpansionPanelListState#421e4):
'package:flutter/src/material/mergeable_material.dart': Failed assertion: line 462 pos 18:
'_children[j] is MaterialGap': 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.md

The relevant error-causing widget was:
  ExpansionPanelList
  ExpansionPanelList:file:///C:/Users/Simon/Documents/flutter_samples/bug_expansion_panel_list/lib/main.dart:116:12

When the exception was thrown, this was the stack:
#2      _MergeableMaterialState.didUpdateWidget (package:flutter/src/material/mergeable_material.dart:462:18)
#3      StatefulElement.update (package:flutter/src/widgets/framework.dart:5260:55)
#4      Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#5      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#6      StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#7      Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#8      StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#9      Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#10     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:6093:32)
#11     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6595:17)
#12     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#13     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#14     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#15     StatelessElement.update (package:flutter/src/widgets/framework.dart:5162:5)
#16     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#17     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#18     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#19     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#20     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#21     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#22     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#23     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#24     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#25     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#26     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#27     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#28     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#29     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#30     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#31     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#32     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#33     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#34     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#35     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#36     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#37     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#38     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#39     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#40     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#41     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#42     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#43     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#44     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#45     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#46     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#47     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#48     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#49     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#50     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#51     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#52     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#53     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#54     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#55     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#56     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#57     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#58     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#59     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#60     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#61     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6442:14)
#62     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#63     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#64     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#65     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#66     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#67     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#68     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#69     ProxyElement.update (package:flutter/src/widgets/framework.dart:5417:5)
#70     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#71     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#72     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#73     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#74     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#75     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#76     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#77     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#78     StatelessElement.update (package:flutter/src/widgets/framework.dart:5162:5)
#79     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#80     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#81     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#82     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#83     StatefulElement.update (package:flutter/src/widgets/framework.dart:5274:5)
#84     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#85     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#86     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#87     StatelessElement.update (package:flutter/src/widgets/framework.dart:5162:5)
#88     Element.updateChild (package:flutter/src/widgets/framework.dart:3686:15)
#89     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5111:16)
#90     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11)
#91     Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7)
#92     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2780:19)
#93     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:903:21)
#94     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:358:5)
#95     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1284:15)
#96     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1214:9)
#97     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:1072:5)
#98     _invoke (dart:ui/hooks.dart:142:13)
#99     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:359:5)
#100    _drawFrame (dart:ui/hooks.dart:112:31)
(elided 2 frames from class _AssertionError)

════════════════════════════════════════════════════════════════════════════════════════════════════

Flutter Doctor output

Doctor output
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.10.2, on Microsoft Windows [Version 10.0.19045.2965], locale de-DE)
[√] Windows Version (Installed version of Windows is version 10 or higher)
[√] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.5.5)   
[√] Android Studio (version 2022.2)
[√] IntelliJ IDEA Community Edition (version 2023.1)
[√] VS Code (version 1.79.0)
[√] Connected device (3 available)
[√] Network resources

• No issues found!

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: error messageError messages from the Flutter frameworkf: material designflutter/packages/flutter/material repository.found in release: 3.10Found to occur in 3.10found in release: 3.12Found to occur in 3.12frameworkflutter/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 version

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions