Skip to content

Add error handling for Element lifecycle user callbacks #173148

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Aug 14, 2025

Conversation

LongCatIsLooong
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong commented Aug 2, 2025

This is for #172289, but since this fix is speculative so I'll wait for the confirmation from the original reporters before closing the issue.

As a bonus this fixes #65655

The framework Element rebuild logic relies heavily on Element._lifecycleState being correct. When a user-supplied lifecycle callback (e.g., State.deactivate) fails the framework currently only ensures that every Element in the tree has the right lifecycle state, so an out-of-tree Element that is supposed to be disposed may still have an active state and continue being rebuilt by the BuildScope (because it's in the dirty list). See the comments in #172289

Also related:
#100777
Internal:
b/425298525 b/431537277
b/300829376 b/415724119 b/283614822

TODO (in a different PR)

The original issue could also be caused by incorrect Element.updateChild calls. If an Element subclass calls Element.updateChild to add child but forgets to update its child list accordingly (such that visitChildren misses that child), you'll get a child Element that thinks it's a child of the parent but the parent doesn't recognize the child so won't take that child into account during reparenting or unmounting. This is a programmer error that we should try to catch in the framework.

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

@github-actions github-actions bot added the framework flutter/packages/flutter repository. See also f: labels. label Aug 2, 2025
@@ -2059,7 +2059,7 @@ abstract class RenderObject with DiagnosticableTreeMixin implements HitTestTarge
assert(child._parent == this);
assert(child.attached == attached);
assert(child.parentData != null);
if (!(_isRelayoutBoundary ?? true)) {
if (!(child._isRelayoutBoundary ?? true)) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated change. This is a typo from #169958

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces robust error handling for Element lifecycle callbacks, specifically for deactivate, to prevent framework state corruption when user-provided code throws an exception. The use of try...finally blocks to ensure critical framework logic executes is a solid approach. The refactoring of Element.deactivate into a public hook and a private implementation is also a clean and effective pattern. The new tests are valuable and cover the intended failure scenarios well. I have one minor suggestion in a test file to remove a redundant line.

@@ -5757,6 +5777,10 @@ abstract class ComponentElement extends Element {
],
),
);
// _Make sure the old child subtree are deactivated and disposed.
try {
Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't enough. If you inflate a widget during the process and a descendant Element fails to activate, the current pattern in framework.dart is to replace the entire subtree rooted at the performRebuild call with an ErrorWidget. So some inflated elements are still active (since the inflation process was partially successful) even if they never get incorporated into the tree.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only a best effort thing? should we have a catch or finally to clean up the reset of tree?

Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I guess if activation fails we should also build the ErrorWidget to replace the subtree that actually failed to re-activate instead of that subtree that we're trying to inflate. Updating.
Edit: I ended up just deactivating the whole tree that will be replaced by this ErrorWidget.

try {
element.deactivate();
} catch (_) {
element._ensureDeactivated();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may potentially be called twice if the crash is in _ensureDeactivated

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't think this is an issue though, but may make stack trace a bit messy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried removing the "ensure" part out of deactivate but one of our tests is calling deactivate directly so I couldnt. See #173148 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I think this is fine

@@ -5757,6 +5777,10 @@ abstract class ComponentElement extends Element {
],
),
);
// _Make sure the old child subtree are deactivated and disposed.
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only a best effort thing? should we have a catch or finally to clean up the reset of tree?

@LongCatIsLooong LongCatIsLooong marked this pull request as draft August 4, 2025 23:53
@LongCatIsLooong LongCatIsLooong marked this pull request as ready for review August 5, 2025 18:14
@github-actions github-actions bot added f: material design flutter/packages/flutter/material repository. f: cupertino flutter/packages/flutter/cupertino repository labels Aug 5, 2025
return newChild;
}
} catch (_) {
// Attempt to do some clean-up if activation or mount fails to leave tree in a reasonable state.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous implementation only tries to do that if _activateWithparent fails.

@@ -4708,11 +4721,21 @@ abstract class Element extends DiagnosticableTree implements BuildContext {
/// Implementations of this method should end with a call to the inherited
/// method, as in `super.deactivate()`.
@mustCallSuper
@visibleForOverriding
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the annotation because I was trying to move _ensureDeactivated out, but since nothing is failing I'll keep the annotation (same as activate).

@github-actions github-actions bot added the f: routes Navigator, Router, and related APIs. label Aug 6, 2025
/// build phase.
inactive,

/// The [Element] encountered a unrecoverable error while being rebuilt when it
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// The [Element] encountered a unrecoverable error while being rebuilt when it
/// The [Element] encountered an unrecoverable error while being rebuilt when it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are great docs btw, thanks for adding them :)

/// This indicates the [Element]'s subtree is in an inconsistent state and must
/// not be re-incorporated into the tree again.
///
/// When a unrecoverable error is encountered, the framework calls
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// When a unrecoverable error is encountered, the framework calls
/// When an unrecoverable error is encountered, the framework calls

@LongCatIsLooong
Copy link
Contributor Author

I introduced a new lifecycle state for Elements that failed to mount / activate, because while we still need to try to deactivate such Elements, we may not need to dispose them or rethrow exceptions encountered during deactivation like other Elements, so the new state is used by the framework to decide which callpath to take.

I decided not to dispose these Elements because they might have never called initState, so failed is a terminal state and it doesn't transition to defunct and I think that information could be useful in the future for debugging purposes.

element._ensureDeactivated();
// Do not rethrow:
// The subtree has already thrown a different error and the framework is
// cleaning up on a best-effort basis.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "best-effort basis" here may sound a bit scary, as the failing widget subtree may end up with different states with assertions enabled / disabled (and the framework don't rethrow). But I think the goal is to make sure the Elements are in the correct state as far as the framework is concerned when something fails, to reduce the noise in the crash report. Maybe we should only call _ensureDeactivated instead so we don't invoke user deactivate callbacks?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

widget subtree may end up with different states with assertions enabled / disabled

won't they all become failed at the end?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh by "end up with different states" I didn't mean ElementLifecycleState. I was just a bit worried that in debug mode some calls could have been skipped because of an assertion fired in the deactivate implementation so it returned early (and the failures are silenced), but in production these calls will actually happen which can do more damages. But now I think about it if the developer saw that bug in debug mode they should just fix that unhandled exception.

Also I tried _ensureDeactivated it ended up throwing a brunch of other errors during unmount in some tests so I'll keep the current implementation.

}
}

static void _deactivateFailedSubtreeRecursively(Element element) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be call during production as well? I think so, but just want to double check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

/// This is one of the two final stages of the element lifecycle and is not
/// reversible. Reaching this state typically means that a widget implementation
/// is throwing unhandled exceptions that need to be properly handled.
failed,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

failedToActivate

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What exactly happen ad the end of this? do they just hang there without getting disposed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes because we don't know what to do with them, they will be stuck in a limbo. Some may have failed before initState was called so these Elements are not disposable, and others may have not gone through proper deactivation. The decision to not dispose them is pretty arbitrary, but since these elements are in inconsistent states I don't know if one option will be better than other, as they will be equally bad.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer the current name since it could also be fail to deactivate?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a code path to put element in this state when they fail to deactivate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, in _InactiveElements._deactivateRecursively, Element._deactivateFailedSubtreeRecursively(element); is called if the element fails to deactivate (and the deactivation exception will be rethrown).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gotcha, thanks

try {
_deactivateRecursively(element);
} finally {
_elements.add(element);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the element failed to deactivate do we still want to add it to the elements?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point I restructured the deactivate flow, now I don't think an element will be added to the list if it fails to deactivate.

return updatedChild!;
} else {
newChild.mount(this, newSlot);
assert(newChild._lifecycleState == _ElementLifecycle.active);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't be _ElementLifecycle.failed and go to catch case right? maybe we should assert that in catch case. I don't think that is possible, but probably should be safe

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With asserts enabled, the new code would still rethrow the assert like it should if the resulting lifecycle state is not active? (maybe I'm not understanding the question correctly)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if the lifecycle is anything other than active, this will go to the catch and go through the _deactivateFailedChildSilently. I was just thinking that in the catch body before it goes o _deactivateFailedChildSilently, can we add an assert(newChild._lifecycleState != _ElementLifecycle.failed) to make sure an element doesn't somhow get _deactivateFailedChildSilently twice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh you mean adding assert(newChild._lifecycleState != _ElementLifecycle.failed) to the catch clause below? But if that assert fires if will prevent the "real" exception from being rethrow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably fine for something to get _deactivateFailedChildSilently'd twice (but it seems unlikely)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah this is fine.

assert(newChild._lifecycleState == _ElementLifecycle.active);
return newChild;
}
} catch (_) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we use (_) in our repo? i thought this is against style guide

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using wildcard in pattern matching is fine? Here I'd consider the _ to be a wildcard pattern instead of anonymous argument since the catch clause is pretty pattern-match-y.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I looked at dart's syntax again:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

It doesn't look like that _ is being used as a wildcard identifier, as the pattern matching is expressed in the on clause. So the (_) here probably is an anonymous identifier / argument.

But I think I just copied that from the existing implementation:

} catch (_) {
// Attempt to do some clean-up if activation fails to leave tree in a reasonable state.
try {
deactivateChild(newChild);
} catch (_) {
// Clean-up failed. Only surface original exception.
}
rethrow;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried replacing _ with an identifier there's an "emply_catch_block" lint that doesn't like that change. Also the style guide says:

Provide full type information and names even for parameters that are otherwise unused. This makes it easier for people reading the code to tell what is actually going on (e.g. what is being ignored).

But catch (e) isn't any more informative than catch (_) I think.

element._ensureDeactivated();
// Do not rethrow:
// The subtree has already thrown a different error and the framework is
// cleaning up on a best-effort basis.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

widget subtree may end up with different states with assertions enabled / disabled

won't they all become failed at the end?

_deactivateRecursively(element);
// This element is only added to _elements if the whole subtree is
// successfully deactivated.
_elements.add(element);
Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a descendant fails to deactivate, the root won't be marked as .failed here (it's still .inactive). The caller (of Element.deactivateChild) may catch the exception and marked the entire subtree as failed like inflateWidget does.

Copy link
Contributor Author

@LongCatIsLooong LongCatIsLooong Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the caller doesn't do that it should still be fine. The element will get stuck in the inactive state forever.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at the updateChild, it only mark the newChild to failed, instead of existing child (which got deactivated). or did I miss something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry can you point me to the line that this is happening? IIRC updateChild doesn't have any try ... catch blocks in it so it simply rethrows everything. If a descendant element of the existing child fails to deactivate the updateChild method is going to return immediately, so it won't even get a chance to call inflateWidget to create the new child as far as I can tell.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm, this is answered in other thread

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replied to some of the thread. I think the code looks mostly fine, just some questions

Copy link
Contributor

@chunhtai chunhtai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Aug 14, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Aug 14, 2025
Merged via the queue into flutter:master with commit 2fcda04 Aug 14, 2025
75 checks passed
@flutter-dashboard flutter-dashboard bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Aug 14, 2025
SydneyBao pushed a commit to SydneyBao/flutter that referenced this pull request Aug 14, 2025
…3148)

This is for flutter#172289, but since this fix is speculative so I'll wait for
the confirmation from the original reporters before closing the issue.

As a bonus this fixes flutter#65655

The framework Element rebuild logic relies heavily on
`Element._lifecycleState` being correct. When a user-supplied lifecycle
callback (e.g., `State.deactivate`) fails the framework currently only
ensures that every `Element` in the tree has the right lifecycle state,
so an out-of-tree `Element` that is supposed to be disposed may still
have an `active` state and continue being rebuilt by the BuildScope
(because it's in the dirty list). See the comments in flutter#172289

Also related:
flutter#100777
Internal:
b/425298525 b/431537277
b/300829376 b/415724119 b/283614822

# TODO (in a different PR)
The original issue could also be caused by incorrect
`Element.updateChild` calls. If an `Element` subclass calls
`Element.updateChild` to add child but forgets to update its child list
accordingly (such that `visitChildren` misses that child), you'll get a
child Element that thinks it's a child of the parent but the parent
doesn't recognize the child so won't take that child into account during
reparenting or unmounting. This is a programmer error that we should try
to catch in the framework.

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] 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.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[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
@LongCatIsLooong LongCatIsLooong deleted the deactivate-throw branch August 14, 2025 22:56
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2025
auto-submit bot pushed a commit to flutter/packages that referenced this pull request Aug 15, 2025
flutter/flutter@f4334d2...52af7a5

2025-08-15 engine-flutter-autoroll@skia.org Roll Packages from 09533b7 to 5c52c55 (6 revisions) (flutter/flutter#173854)
2025-08-15 engine-flutter-autoroll@skia.org Roll Skia from 46ec77ae3954 to 5654ac32ede0 (1 revision) (flutter/flutter#173848)
2025-08-15 engine-flutter-autoroll@skia.org Roll Skia from 162f47d6b6bd to 46ec77ae3954 (2 revisions) (flutter/flutter#173833)
2025-08-15 engine-flutter-autoroll@skia.org Roll Dart SDK from c7faab270f27 to cc008dc8e7aa (2 revisions) (flutter/flutter#173826)
2025-08-15 engine-flutter-autoroll@skia.org Roll Skia from ad5d04000101 to 162f47d6b6bd (5 revisions) (flutter/flutter#173822)
2025-08-15 jason-simmons@users.noreply.github.com Update the RBE configuration for the recent Clang update (flutter/flutter#173803)
2025-08-15 matanlurey@users.noreply.github.com Stop writing legacy `FLUTTER_ROOT/version` file (by default?) (flutter/flutter#172793)
2025-08-15 matanlurey@users.noreply.github.com Remove `luci_flags.parallel_download_builds` and friends (flutter/flutter#173799)
2025-08-14 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Predictive back route transitions by default (#165832)" (flutter/flutter#173809)
2025-08-14 engine-flutter-autoroll@skia.org Roll Skia from dca5f05fee87 to ad5d04000101 (8 revisions) (flutter/flutter#173798)
2025-08-14 mdebbar@google.com [web] Cleanup usages of deprecated `routeUpdated` message (flutter/flutter#173782)
2025-08-14 ahmedsameha1@gmail.com Make sure that DataTable, DataColumn, DataRow, and DataCell don't crash in 0x0 environment (flutter/flutter#173515)
2025-08-14 ahmedsameha1@gmail.com Make sure that a TableRowInkWell doesn't crash in 0x0 environment (flutter/flutter#173627)
2025-08-14 ahmedsameha1@gmail.com Make sure that a DatePickerDialog doesn't crash in 0x0 environment (flutter/flutter#173677)
2025-08-14 robert.ancell@canonical.com Return result of setting OpenGL contexts back to Flutter (flutter/flutter#173757)
2025-08-14 matanlurey@users.noreply.github.com Read `bin/cache/flutter.version.json` instead of `version` for `flutter_gallery` (flutter/flutter#173797)
2025-08-14 jmccandless@google.com Predictive back route transitions by default (flutter/flutter#165832)
2025-08-14 houssemeddinefadhli81@gmail.com feat: add onLongPressUp callback to InkWell widget (flutter/flutter#173221)
2025-08-14 engine-flutter-autoroll@skia.org Roll Dart SDK from 214a7f829913 to c7faab270f27 (1 revision) (flutter/flutter#173792)
2025-08-14 31859944+LongCatIsLooong@users.noreply.github.com Add error handling for `Element` lifecycle user callbacks (flutter/flutter#173148)
2025-08-14 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from I1TfNmsqTp7t3rO8e... to zWRpLglb48zC1vZLv... (flutter/flutter#173784)
2025-08-14 jhy03261997@gmail.com [Range slider] Tap on active range,  the thumb closest to the mouse cursor should move to the cursor position. (flutter/flutter#173725)
2025-08-14 engine-flutter-autoroll@skia.org Roll Packages from 6cb9113 to 09533b7 (4 revisions) (flutter/flutter#173789)
2025-08-14 ttankkeo112@gmail.com Implements the Android native stretch effect as a fragment shader (Impeller-only). (flutter/flutter#169293)
2025-08-14 matanlurey@users.noreply.github.com Sync `CHANGELOG.md` (3.35 -> `master`) (flutter/flutter#173790)
2025-08-14 victorsanniay@gmail.com [VPAT][A11y] Announce Autocomplete search results status (flutter/flutter#173480)
2025-08-14 bruno.leroux@gmail.com Fix InputDecorator label padding (flutter/flutter#173344)
2025-08-14 edwinzn9@gmail.com Fix default minimumSize in dropdownMenu when maximumSize is null (flutter/flutter#169438)
2025-08-14 matanlurey@users.noreply.github.com Thread sub-builders for every engine-uploading builder (flutter/flutter#173742)

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 louisehsu@google.com,stuartmorgan@google.com 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
ksokolovskyi pushed a commit to ksokolovskyi/flutter that referenced this pull request Aug 19, 2025
…3148)

This is for flutter#172289, but since this fix is speculative so I'll wait for
the confirmation from the original reporters before closing the issue.

As a bonus this fixes flutter#65655

The framework Element rebuild logic relies heavily on
`Element._lifecycleState` being correct. When a user-supplied lifecycle
callback (e.g., `State.deactivate`) fails the framework currently only
ensures that every `Element` in the tree has the right lifecycle state,
so an out-of-tree `Element` that is supposed to be disposed may still
have an `active` state and continue being rebuilt by the BuildScope
(because it's in the dirty list). See the comments in flutter#172289

Also related:
flutter#100777
Internal:
b/425298525 b/431537277
b/300829376 b/415724119 b/283614822

# TODO (in a different PR)
The original issue could also be caused by incorrect
`Element.updateChild` calls. If an `Element` subclass calls
`Element.updateChild` to add child but forgets to update its child list
accordingly (such that `visitChildren` misses that child), you'll get a
child Element that thinks it's a child of the parent but the parent
doesn't recognize the child so won't take that child into account during
reparenting or unmounting. This is a programmer error that we should try
to catch in the framework.

## Pre-launch Checklist

- [ ] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [ ] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [ ] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [ ] I signed the [CLA].
- [ ] I listed at least one issue that this PR fixes in the description
above.
- [ ] I updated/added relevant documentation (doc comments with `///`).
- [ ] 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.
- [ ] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

**Note**: The Flutter team is currently trialing the use of [Gemini Code
Assist for
GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code).
Comments from the `gemini-code-assist` bot should not be taken as
authoritative feedback from the Flutter team. If you find its comments
useful you can update your code accordingly, but if you are unsure or
disagree with the feedback, please feel free to wait for a Flutter team
member's review for guidance on which automated comments should be
addressed.

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[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
WillBLogical pushed a commit to WillBLogical/packages that referenced this pull request Aug 20, 2025
…r#9832)

flutter/flutter@f4334d2...52af7a5

2025-08-15 engine-flutter-autoroll@skia.org Roll Packages from 09533b7 to 5c52c55 (6 revisions) (flutter/flutter#173854)
2025-08-15 engine-flutter-autoroll@skia.org Roll Skia from 46ec77ae3954 to 5654ac32ede0 (1 revision) (flutter/flutter#173848)
2025-08-15 engine-flutter-autoroll@skia.org Roll Skia from 162f47d6b6bd to 46ec77ae3954 (2 revisions) (flutter/flutter#173833)
2025-08-15 engine-flutter-autoroll@skia.org Roll Dart SDK from c7faab270f27 to cc008dc8e7aa (2 revisions) (flutter/flutter#173826)
2025-08-15 engine-flutter-autoroll@skia.org Roll Skia from ad5d04000101 to 162f47d6b6bd (5 revisions) (flutter/flutter#173822)
2025-08-15 jason-simmons@users.noreply.github.com Update the RBE configuration for the recent Clang update (flutter/flutter#173803)
2025-08-15 matanlurey@users.noreply.github.com Stop writing legacy `FLUTTER_ROOT/version` file (by default?) (flutter/flutter#172793)
2025-08-15 matanlurey@users.noreply.github.com Remove `luci_flags.parallel_download_builds` and friends (flutter/flutter#173799)
2025-08-14 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Predictive back route transitions by default (#165832)" (flutter/flutter#173809)
2025-08-14 engine-flutter-autoroll@skia.org Roll Skia from dca5f05fee87 to ad5d04000101 (8 revisions) (flutter/flutter#173798)
2025-08-14 mdebbar@google.com [web] Cleanup usages of deprecated `routeUpdated` message (flutter/flutter#173782)
2025-08-14 ahmedsameha1@gmail.com Make sure that DataTable, DataColumn, DataRow, and DataCell don't crash in 0x0 environment (flutter/flutter#173515)
2025-08-14 ahmedsameha1@gmail.com Make sure that a TableRowInkWell doesn't crash in 0x0 environment (flutter/flutter#173627)
2025-08-14 ahmedsameha1@gmail.com Make sure that a DatePickerDialog doesn't crash in 0x0 environment (flutter/flutter#173677)
2025-08-14 robert.ancell@canonical.com Return result of setting OpenGL contexts back to Flutter (flutter/flutter#173757)
2025-08-14 matanlurey@users.noreply.github.com Read `bin/cache/flutter.version.json` instead of `version` for `flutter_gallery` (flutter/flutter#173797)
2025-08-14 jmccandless@google.com Predictive back route transitions by default (flutter/flutter#165832)
2025-08-14 houssemeddinefadhli81@gmail.com feat: add onLongPressUp callback to InkWell widget (flutter/flutter#173221)
2025-08-14 engine-flutter-autoroll@skia.org Roll Dart SDK from 214a7f829913 to c7faab270f27 (1 revision) (flutter/flutter#173792)
2025-08-14 31859944+LongCatIsLooong@users.noreply.github.com Add error handling for `Element` lifecycle user callbacks (flutter/flutter#173148)
2025-08-14 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from I1TfNmsqTp7t3rO8e... to zWRpLglb48zC1vZLv... (flutter/flutter#173784)
2025-08-14 jhy03261997@gmail.com [Range slider] Tap on active range,  the thumb closest to the mouse cursor should move to the cursor position. (flutter/flutter#173725)
2025-08-14 engine-flutter-autoroll@skia.org Roll Packages from 6cb9113 to 09533b7 (4 revisions) (flutter/flutter#173789)
2025-08-14 ttankkeo112@gmail.com Implements the Android native stretch effect as a fragment shader (Impeller-only). (flutter/flutter#169293)
2025-08-14 matanlurey@users.noreply.github.com Sync `CHANGELOG.md` (3.35 -> `master`) (flutter/flutter#173790)
2025-08-14 victorsanniay@gmail.com [VPAT][A11y] Announce Autocomplete search results status (flutter/flutter#173480)
2025-08-14 bruno.leroux@gmail.com Fix InputDecorator label padding (flutter/flutter#173344)
2025-08-14 edwinzn9@gmail.com Fix default minimumSize in dropdownMenu when maximumSize is null (flutter/flutter#169438)
2025-08-14 matanlurey@users.noreply.github.com Thread sub-builders for every engine-uploading builder (flutter/flutter#173742)

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 louisehsu@google.com,stuartmorgan@google.com 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Throwing in didChangeDependencies after establishing dependencies causes failures during test teardown
3 participants