Fix AnimatedList.separated assert when removing last item mid-removal…#186389
Merged
mbcorona merged 1 commit intoMay 20, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request fixes an assertion failure in AnimatedList.separated that occurred when removing the last item while a previous removal animation was still active. The fix involves introducing _outgoingItemsCount to accurately determine the current visible item count. A regression test has been added to cover this scenario. Feedback was provided to correct a spelling variation in a comment to match the American English requirement of the style guide.
mbcorona
force-pushed
the
fix-animated-list-separated-186361
branch
from
May 12, 2026 04:05
2fdcd6f to
8871713
Compare
navaronbracke
previously approved these changes
May 12, 2026
| // All removal animations finished and the surviving item is alone. | ||
| expect(find.text('removing item 0'), findsNothing); | ||
| expect(find.text('removing item 2'), findsNothing); | ||
| expect(find.text('item 0'), findsOneWidget); |
Contributor
There was a problem hiding this comment.
Same here for asserting on the two items that are now gone
Member
Author
There was a problem hiding this comment.
Hi @navaronbracke , asserts were added in both places.
mbcorona
force-pushed
the
fix-animated-list-separated-186361
branch
from
May 12, 2026 13:39
8871713 to
6e4a7c7
Compare
QuncCccccc
self-requested a review
May 14, 2026 19:00
navaronbracke
approved these changes
May 20, 2026
This was referenced May 20, 2026
auto-submit Bot
pushed a commit
to flutter/packages
that referenced
this pull request
May 20, 2026
flutter/flutter@259aeae...e03b91f 2026-05-20 [email protected] Roll Packages from ade10ca to 1dfbada (6 revisions) (flutter/flutter#186811) 2026-05-20 [email protected] Fix AnimatedList.separated assert when removing last item mid-removal… (flutter/flutter#186389) 2026-05-20 [email protected] Roll Skia from d45969a5752e to 5f4f454b9662 (2 revisions) (flutter/flutter#186809) 2026-05-20 [email protected] Roll Fuchsia Linux SDK from -F9Ci3Opxt06MixDl... to iKCvaD58jKStYGla0... (flutter/flutter#186796) 2026-05-20 [email protected] Roll Skia from 19ad9707e5c6 to d45969a5752e (2 revisions) (flutter/flutter#186792) 2026-05-20 [email protected] Roll Skia from 3471ebf5af0c to 19ad9707e5c6 (9 revisions) (flutter/flutter#186772) 2026-05-20 [email protected] [web] Refactor webparagraph painters to separate CK properly (flutter/flutter#186684) 2026-05-19 [email protected] Enable Swift testing in the iOS embedder (flutter/flutter#185712) 2026-05-19 [email protected] [web] Rename WebParagraph goldens (flutter/flutter#186680) 2026-05-19 [email protected] Roll Skia from f1b406860c5e to 3471ebf5af0c (5 revisions) (flutter/flutter#186745) 2026-05-19 [email protected] Revert "Ship gen_snapshot for linux-arm64 hosts targeting Android" (flutter/flutter#186693) 2026-05-19 [email protected] [ Tool ] Remove legacy analytics code (flutter/flutter#184994) 2026-05-19 [email protected] Update Vulkan enum values (flutter/flutter#186694) 2026-05-19 [email protected] fix(web): Fixes CSS override detection when the browser has a default font size (flutter/flutter#186474) 2026-05-19 [email protected] adds linux impeller hello world integration test (flutter/flutter#186715) 2026-05-19 [email protected] Update the list of binaries in the code signing verification test to include new Dart snapshots (flutter/flutter#186754) 2026-05-19 [email protected] Make EdgeDraggingAutoScroller respect ScrollPhysics (flutter/flutter#186541) 2026-05-19 [email protected] [ Widget Preview ] Fix inspector split resize focus loss over WebViews (flutter/flutter#186432) 2026-05-19 [email protected] Roll Packages from b9bdd37 to ade10ca (1 revision) (flutter/flutter#186746) 2026-05-19 [email protected] Manual Dart roll from 8e30b88e4d5a to 66873d2da857 (flutter/flutter#186690) 2026-05-19 [email protected] [ Widget Preview ] Improve zoom behavior and add zoom slider (flutter/flutter#186422) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
matthewhendrix
pushed a commit
to matthewhendrix/flutter
that referenced
this pull request
May 23, 2026
flutter#186389) ## Summary `AnimatedList.separated.removeItem` used the sliver's total child count (`_itemsCount`) to decide whether the just-removed item was the last item in the list. That count still includes children animating out from earlier `removeItem` calls, so while a previous removal was in flight the new tail of the visible list was misclassified as a middle item. The separator removal then targeted the wrong index, and once the item being removed was added to `_outgoingItems` the next `_indexToItemIndex` lookup ran past `_itemsCount` and tripped the `itemIndex >= 0 && itemIndex < _itemsCount` assertion inside `_SliverAnimatedMultiBoxAdaptorState.removeItem`. The fix captures `_itemsCount - _outgoingItems.length` before mutating the sliver and uses that visible count for both the "are there enough items to have a separator?" and "is this the new last item?" checks. When no removal is in flight `_outgoingItems` is empty and behavior is unchanged, so existing `.separated` coverage and the `removeAllItems` regression test from flutter#176452 continue to pass. ## Related issues Fixes flutter#186361. Related prior fix for the non-separated `removeAllItems` variant: flutter#176452 (issue flutter#176362). ## Test plan - [x] Added a regression test in `packages/flutter/test/widgets/animated_list_test.dart` that reproduces the assertion on master and passes with this change: starts a 10s removal on a non-last item, pumps part of the animation, then removes the new last item, and asserts no exception is thrown. - [x] `flutter test packages/flutter/test/widgets/animated_list_test.dart packages/flutter/test/widgets/animated_grid_test.dart` — 34 tests pass, including the existing comprehensive `AnimatedList.separated` test and the `removeAllItems` regression test from flutter#176452. - [x] `dart analyze` on the touched files: no issues. - [x] Manually verified with the reproducer from the issue: before the fix the assertion fires in the debug console; after the fix the second removal animates out cleanly. ## AI disclosure Written with assistance from Claude Code (Anthropic). I reviewed every change, ran the tests, and verified the fix manually before submitting. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
creatorpiyush
pushed a commit
to creatorpiyush/packages
that referenced
this pull request
Jun 10, 2026
…r#11747) flutter/flutter@259aeae...e03b91f 2026-05-20 [email protected] Roll Packages from ade10ca to 1dfbada (6 revisions) (flutter/flutter#186811) 2026-05-20 [email protected] Fix AnimatedList.separated assert when removing last item mid-removal… (flutter/flutter#186389) 2026-05-20 [email protected] Roll Skia from d45969a5752e to 5f4f454b9662 (2 revisions) (flutter/flutter#186809) 2026-05-20 [email protected] Roll Fuchsia Linux SDK from -F9Ci3Opxt06MixDl... to iKCvaD58jKStYGla0... (flutter/flutter#186796) 2026-05-20 [email protected] Roll Skia from 19ad9707e5c6 to d45969a5752e (2 revisions) (flutter/flutter#186792) 2026-05-20 [email protected] Roll Skia from 3471ebf5af0c to 19ad9707e5c6 (9 revisions) (flutter/flutter#186772) 2026-05-20 [email protected] [web] Refactor webparagraph painters to separate CK properly (flutter/flutter#186684) 2026-05-19 [email protected] Enable Swift testing in the iOS embedder (flutter/flutter#185712) 2026-05-19 [email protected] [web] Rename WebParagraph goldens (flutter/flutter#186680) 2026-05-19 [email protected] Roll Skia from f1b406860c5e to 3471ebf5af0c (5 revisions) (flutter/flutter#186745) 2026-05-19 [email protected] Revert "Ship gen_snapshot for linux-arm64 hosts targeting Android" (flutter/flutter#186693) 2026-05-19 [email protected] [ Tool ] Remove legacy analytics code (flutter/flutter#184994) 2026-05-19 [email protected] Update Vulkan enum values (flutter/flutter#186694) 2026-05-19 [email protected] fix(web): Fixes CSS override detection when the browser has a default font size (flutter/flutter#186474) 2026-05-19 [email protected] adds linux impeller hello world integration test (flutter/flutter#186715) 2026-05-19 [email protected] Update the list of binaries in the code signing verification test to include new Dart snapshots (flutter/flutter#186754) 2026-05-19 [email protected] Make EdgeDraggingAutoScroller respect ScrollPhysics (flutter/flutter#186541) 2026-05-19 [email protected] [ Widget Preview ] Fix inspector split resize focus loss over WebViews (flutter/flutter#186432) 2026-05-19 [email protected] Roll Packages from b9bdd37 to ade10ca (1 revision) (flutter/flutter#186746) 2026-05-19 [email protected] Manual Dart roll from 8e30b88e4d5a to 66873d2da857 (flutter/flutter#186690) 2026-05-19 [email protected] [ Widget Preview ] Improve zoom behavior and add zoom slider (flutter/flutter#186422) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
via-guy
pushed a commit
to via-guy/flutter
that referenced
this pull request
Jun 26, 2026
flutter#186389) ## Summary `AnimatedList.separated.removeItem` used the sliver's total child count (`_itemsCount`) to decide whether the just-removed item was the last item in the list. That count still includes children animating out from earlier `removeItem` calls, so while a previous removal was in flight the new tail of the visible list was misclassified as a middle item. The separator removal then targeted the wrong index, and once the item being removed was added to `_outgoingItems` the next `_indexToItemIndex` lookup ran past `_itemsCount` and tripped the `itemIndex >= 0 && itemIndex < _itemsCount` assertion inside `_SliverAnimatedMultiBoxAdaptorState.removeItem`. The fix captures `_itemsCount - _outgoingItems.length` before mutating the sliver and uses that visible count for both the "are there enough items to have a separator?" and "is this the new last item?" checks. When no removal is in flight `_outgoingItems` is empty and behavior is unchanged, so existing `.separated` coverage and the `removeAllItems` regression test from flutter#176452 continue to pass. ## Related issues Fixes flutter#186361. Related prior fix for the non-separated `removeAllItems` variant: flutter#176452 (issue flutter#176362). ## Test plan - [x] Added a regression test in `packages/flutter/test/widgets/animated_list_test.dart` that reproduces the assertion on master and passes with this change: starts a 10s removal on a non-last item, pumps part of the animation, then removes the new last item, and asserts no exception is thrown. - [x] `flutter test packages/flutter/test/widgets/animated_list_test.dart packages/flutter/test/widgets/animated_grid_test.dart` — 34 tests pass, including the existing comprehensive `AnimatedList.separated` test and the `removeAllItems` regression test from flutter#176452. - [x] `dart analyze` on the touched files: no issues. - [x] Manually verified with the reproducer from the issue: before the fix the assertion fires in the debug console; after the fix the second removal animates out cleanly. ## AI disclosure Written with assistance from Claude Code (Anthropic). I reviewed every change, ran the tests, and verified the fix manually before submitting. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [AI contribution guidelines] and understand my responsibilities, or I am not using AI tools. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [ ] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [ ] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [AI contribution guidelines]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#ai-contribution-guidelines [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
AnimatedList.separated.removeItemused the sliver's total child count (_itemsCount) to decide whether the just-removed item was the last item in the list. That count still includes children animating out from earlierremoveItemcalls, so while a previous removal was in flight the new tail of the visible list was misclassified as a middle item. The separator removal then targeted the wrong index, and once the item being removed was added to_outgoingItemsthe next_indexToItemIndexlookup ran past_itemsCountand tripped theitemIndex >= 0 && itemIndex < _itemsCountassertion inside_SliverAnimatedMultiBoxAdaptorState.removeItem.The fix captures
_itemsCount - _outgoingItems.lengthbefore mutating the sliver and uses that visible count for both the "are there enough items to have a separator?" and "is this the new last item?" checks. When no removal is in flight_outgoingItemsis empty and behavior is unchanged, so existing.separatedcoverage and theremoveAllItemsregression test from #176452 continue to pass.Related issues
Fixes #186361.
Related prior fix for the non-separated
removeAllItemsvariant: #176452 (issue #176362).Test plan
packages/flutter/test/widgets/animated_list_test.dartthat reproduces the assertion on master and passes with this change: starts a 10s removal on a non-last item, pumps part of the animation, then removes the new last item, and asserts no exception is thrown.flutter test packages/flutter/test/widgets/animated_list_test.dart packages/flutter/test/widgets/animated_grid_test.dart— 34 tests pass, including the existing comprehensiveAnimatedList.separatedtest and theremoveAllItemsregression test from Fix(AnimatedScrollView): exclude outgoing items in removeAllItems #176452.dart analyzeon the touched files: no issues.AI disclosure
Written with assistance from Claude Code (Anthropic). I reviewed every change, ran the tests, and verified the fix manually before submitting.
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.