Skip to content

Explain why initState() is too early to depend on an inherited widget - #192727

Merged
auto-submit[bot] merged 3 commits into
flutter:masterfrom
fahaddoc:fix/105705-depend-on-inherited-before-initstate
Oct 13, 2026
Merged

auto-submit[bot] merged 3 commits into
flutter:masterfrom
fahaddoc:fix/105705-depend-on-inherited-before-initstate

Conversation

@fahaddoc

@fahaddoc fahaddoc commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

When dependOnInheritedWidgetOfExactType() is called before initState() has completed, the error explains the rule like this:

When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.

That last sentence is easy to read as saying the rebuild itself does not see the change, which is what the issue reports as confusing. The rebuild does see it: a widget that depends on an inherited widget is rebuilt when that inherited widget changes, and a build() method that reads it gets the new value. What is never updated is whatever initState() read, because the framework calls initState() only once for each State object and does not call it again for those rebuilds.

This replaces that sentence with the actual reason, and adds the same reason to State.initState's documentation, which told readers not to call dependOnInheritedWidgetOfExactType() there but not why. The ErrorHint that points at build() and didChangeDependencies() is unchanged.

After:

When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. The framework calls initState() only once for each State object and does not call it again for those rebuilds, so a value that initState() reads from an inherited widget is never updated when that inherited widget changes.

The existing test for this error (initState() dependency on Inherited asserts) only checks that something was thrown, so the message itself was untested; the new test covers it. ExpectFail now forwards the caught error so a test can inspect it.

The issue also suggests adding a _StateLifecycle value between created and initialized, set just before initState() is called. I left that out. A State only gets its context after it is constructed (state._element is assigned in the StatefulElement constructor after createState() returns), so the only State code that runs with a context before initState() completes is initState() itself, and a new value would have no constructor case to separate. That is also why the new message no longer mentions constructors; the general advice about constructors stays in the BuildContext.dependOnInheritedWidgetOfExactType docs.

Fixes #105705

Pre-launch Checklist

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

If this change needs to override an active code freeze, provide a comment explaining why. The code freeze workflow can be overridden by code reviewers. See pinned issues for any active code freezes with guidance.

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 Sep 14, 2026

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

Copy link
Copy Markdown
Contributor

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 updates the documentation and error messages in 'framework.dart' to clarify that 'initState' is called only once per 'State' object and is not re-run when an inherited widget changes, meaning values read within it are never updated. It also updates 'inherited_test.dart' to include a regression test verifying that the error message thrown when accessing an inherited widget in 'initState' correctly explains this behavior. There are no review comments, and thus no feedback is provided.

@victorsanni

Copy link
Copy Markdown
Contributor

Hi, please remember to re-request a review when you have made changes to your PRs, so it can re-enter my review queue. Else I don't see that your PR has been updated and can't leave a review.

@victorsanni victorsanni added the CICD Run CI/CD label Sep 28, 2026
@victorsanni
victorsanni self-requested a review September 28, 2026 18:51
@fahaddoc fahaddoc closed this Sep 30, 2026
@fahaddoc fahaddoc reopened this Sep 30, 2026
@fluttergithubbot

Copy link
Copy Markdown
Contributor

An existing Git SHA, 3dc747c833300d80998cbe571e8bc88560afad46, was detected, and no actions were taken.

To re-trigger presubmits after closing or re-opeing a PR, or pushing a HEAD commit (i.e. with --force) that already was pushed before, push a blank commit (git commit --allow-empty -m "Trigger Build") or rebase to continue.

victorsanni
victorsanni previously approved these changes Oct 6, 2026

@victorsanni victorsanni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM with nits.

@Renzo-Olivares
Renzo-Olivares self-requested a review October 7, 2026 00:41
Renzo-Olivares
Renzo-Olivares previously approved these changes Oct 7, 2026

@Renzo-Olivares Renzo-Olivares left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM modulo @victorsanni comments.

@fahaddoc
fahaddoc dismissed stale reviews from Renzo-Olivares and victorsanni via 8a4866e October 9, 2026 14:22
@flutter-dashboard flutter-dashboard Bot removed the CICD Run CI/CD label Oct 9, 2026
@fahaddoc
fahaddoc requested a review from victorsanni October 9, 2026 14:25
@fahaddoc

Copy link
Copy Markdown
Contributor Author

@victorsanni Thanks for the re-review. Two things left on this one, neither of which I can do from my side.

Google testing is failing on 8a4866e (go/frob_pr/192727, completed earlier today). I can't see the run, so flagging it rather than guessing. One thing worth checking first: this PR changes the ErrorDescription text in the dependOnInheritedElement assertion, so an internal test asserting on the old wording would explain it:

its dependent widgets are rebuilt. If the dependent widget's reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget.

If that is what it is, I'm happy to adjust the new wording to whatever keeps the internal tests working, or the test can be updated on your side — whichever you prefer.

The CICD label came off when I pushed the test fold, so Awaiting CICD label is stuck pending. Could you re-add it? Everything else is green.

@Renzo-Olivares Renzo-Olivares left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

The error thrown when dependOnInheritedWidgetOfExactType() is called
before initState() completes said that "the rebuilt dependent widget
will not reflect the changes in the inherited widget", which is not what
happens: the widget is rebuilt and its build() method does see the new
value. What is never updated is whatever initState() read, because
initState() runs once and is not run again when a dependency changes.

State.initState's documentation already said not to use
dependOnInheritedWidgetOfExactType there, but did not say why.
The sentence this PR added to State.initState said the framework calls
it "only once" without saying once per what. Say "only once for each
[State] object", matching "exactly once for each [State] object it
creates" at the top of the same doc, and say that the value that is
never updated is one read from an inherited widget. Use the same
wording in the error text and in the test that checks it.

Also drop the whitespace collapsing in that test. FlutterError's
toString() does not wrap lines, so the comment explaining it was wrong.
Both pumped the same TestInherited(child: ExpectFail(...)) tree. The
flutter#5491 test only checked that an exception was caught, which the error
assertions in the flutter#105705 test already cover, so they are now a single
test carrying both regression references.
@Renzo-Olivares
Renzo-Olivares force-pushed the fix/105705-depend-on-inherited-before-initstate branch from 8a4866e to e09253f Compare October 13, 2026 09:11
@Renzo-Olivares Renzo-Olivares added the CICD Run CI/CD label Oct 13, 2026
@victorsanni victorsanni added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 13, 2026
@auto-submit
auto-submit Bot added this pull request to the merge queue Oct 13, 2026
Merged via the queue into flutter:master with commit d2e5f21 Oct 13, 2026
29 checks passed
@flutter-dashboard flutter-dashboard Bot removed the autosubmit Merge PR when tree becomes green via auto submit App label Oct 13, 2026
auto-submit Bot pushed a commit to flutter/packages that referenced this pull request Oct 14, 2026
Roll Flutter from 4249ccbc18a3 to 426be968b5eb (44 revisions)

flutter/flutter@4249ccb...426be96

2026-10-14 awolff@google.com Allow color delta tolerance in in-memory fuzzy image comparator (flutter/flutter#193937)
2026-10-14 zhongliu88889@gmail.com [web] Drop stale composing range after text is replaced mid-composition (flutter/flutter#194096)
2026-10-14 engine-flutter-autoroll@skia.org Roll Skia from 2a2bbea66844 to acde3755d2e2 (1 revision) (flutter/flutter#194376)
2026-10-14 engine-flutter-autoroll@skia.org Roll Skia from 128c983b12de to 2a2bbea66844 (1 revision) (flutter/flutter#194371)
2026-10-14 engine-flutter-autoroll@skia.org Roll Skia from 48a294ed4955 to 128c983b12de (3 revisions) (flutter/flutter#194353)
2026-10-14 kevmoo@users.noreply.github.com feat(flutter_tools): extract WebDebugConfig from DebuggingOptions (flutter/flutter#194312)
2026-10-14 engine-flutter-autoroll@skia.org Roll Skia from ea6781c5b6d1 to 48a294ed4955 (2 revisions) (flutter/flutter#194349)
2026-10-14 chingjun@google.com Include <vector> in Android proc_table.h. (flutter/flutter#194325)
2026-10-14 engine-flutter-autoroll@skia.org Roll Dart SDK from 5933cb486b4a to 6b50116630d0 (28 revisions) (flutter/flutter#194341)
2026-10-14 97480502+b-luk@users.noreply.github.com Move GLES3 instancing API entry points to FOR_EACH_IMPELLER_GLES3_PROC (flutter/flutter#194319)
2026-10-14 kevmoo@users.noreply.github.com feat(flutter_tools): extract AndroidGradleConfig and move toGradleConfig to AndroidBuildInfo (flutter/flutter#194016)
2026-10-14 engine-flutter-autoroll@skia.org Roll Skia from ae297bec6012 to ea6781c5b6d1 (8 revisions) (flutter/flutter#194331)
2026-10-14 bkonyi@google.com [flutter_tools] Migrate gradle_errors and deferred_components_prebuild_validator away from globals (flutter/flutter#193649)
2026-10-14 kevmoo@users.noreply.github.com [Impeller] Cache GLES sampler configuration in RenderPassStateCache (flutter/flutter#193922)
2026-10-14 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#194332)
2026-10-13 bkonyi@google.com [tool] Migrate RunCommand to modular dependency injection (flutter/flutter#190791)
2026-10-13 mdebbar@google.com Include `engine/src/flutter/.ci.yaml` in quarterly `goldctl` checklist (flutter/flutter#194316)
2026-10-13 nshahan@google.com [flutter_tools] Remove the last AMD module system support (flutter/flutter#193607)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from 8b3394a60654 to ae297bec6012 (5 revisions) (flutter/flutter#194310)
2026-10-13 zhongliu88889@gmail.com [web] Remove the a11y placeholder only after the gesture ends (flutter/flutter#194109)
2026-10-13 mdebbar@google.com Upgrade goldctl to the latest version (flutter/flutter#193932)
2026-10-13 bkonyi@google.com [flutter_tools] Lazily initialize AndroidStudio validation and optimize candidate selection (flutter/flutter#191968)
2026-10-13 68429735+Vonarian@users.noreply.github.com [flutter_tools] Clean up outdated widget preview TODOs and refactor static state (flutter/flutter#189437)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from e5b5db6d0d6f to 8b3394a60654 (2 revisions) (flutter/flutter#194306)
2026-10-13 matt.boetger@gmail.com Redistribute TESTOWNERS for Android team (flutter/flutter#193861)
2026-10-13 kevmoo@users.noreply.github.com feat(flutter_tools): introduce Test and Drive specification objects (flutter/flutter#194017)
2026-10-13 santoshakil@users.noreply.github.com [Impeller] Keep the aspect ratio when shrinking images to the max texture size (flutter/flutter#194010)
2026-10-13 pq@users.noreply.github.com [flutter tool] preserve inherited `DASH__SUPPRESS_ANALYTICS=true` for sub-tools (flutter/flutter#194261)
2026-10-13 engine-flutter-autoroll@skia.org Roll Packages from d8d9e97 to a1ed23c (9 revisions) (flutter/flutter#194302)
2026-10-13 manjian2006@gmail.com Use PE/COFF AOT snapshots for Windows x64 (flutter/flutter#187594)
2026-10-13 omar.alshyokh@gmail.com Fix Expansible crash when PageStorage holds a non-bool value (flutter/flutter#192195)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from ffeccb3ca58a to e5b5db6d0d6f (1 revision) (flutter/flutter#194297)
2026-10-13 49402500+fahaddoc@users.noreply.github.com Explain why initState() is too early to depend on an inherited widget (flutter/flutter#192727)
2026-10-13 victorsanniay@gmail.com Refactor TestPlatformDispatcher (flutter/flutter#192747)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from 3de0984208ec to ffeccb3ca58a (2 revisions) (flutter/flutter#194291)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from 0580c2b780f6 to 3de0984208ec (2 revisions) (flutter/flutter#194281)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from f641d55e07a8 to 0580c2b780f6 (3 revisions) (flutter/flutter#194275)
2026-10-13 engine-flutter-autoroll@skia.org Roll Skia from 0e5d8d1be81b to f641d55e07a8 (1 revision) (flutter/flutter#194266)
2026-10-13 victorsanniay@gmail.com Scaffold view metrics overrides (flutter/flutter#192764)
2026-10-13 kevmoo@users.noreply.github.com [web] Add SemanticsRole.listBox and SemanticsRole.option (flutter/flutter#192971)
2026-10-13 15619084+vashworth@users.noreply.github.com Pin mac_unopt to macOS 15 (flutter/flutter#194254)
2026-10-13 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#194257)
2026-10-12 engine-flutter-autoroll@skia.org Roll Skia from 17f6986c226c to 0e5d8d1be81b (4 revisions) (flutter/flutter#194249)
2026-10-12 97480502+b-luk@users.noreply.github.com Make DisplayLists' use of DlPaint, SkPaint, and impeller::Paint agree on the default isAntiAlias (flutter/flutter#193939)

If this roll has caused a breakage, revert this CL and set the roller
...
suryaKommana2662 pushed a commit to suryaKommana2662/flutter that referenced this pull request Oct 29, 2026
…flutter#192727)

When `dependOnInheritedWidgetOfExactType()` is called before
`initState()` has completed, the error explains the rule like this:

> When an inherited widget changes, for example if the value of
Theme.of() changes, its dependent widgets are rebuilt. If the dependent
widget's reference to the inherited widget is in a constructor or an
initState() method, then the rebuilt dependent widget will not reflect
the changes in the inherited widget.

That last sentence is easy to read as saying the rebuild itself does not
see the change, which is what the issue reports as confusing. The
rebuild does see it: a widget that depends on an inherited widget is
rebuilt when that inherited widget changes, and a `build()` method that
reads it gets the new value. What is never updated is whatever
`initState()` read, because the framework calls `initState()` only once
for each `State` object and does not call it again for those rebuilds.

This replaces that sentence with the actual reason, and adds the same
reason to `State.initState`'s documentation, which told readers not to
call `dependOnInheritedWidgetOfExactType()` there but not why. The
`ErrorHint` that points at `build()` and `didChangeDependencies()` is
unchanged.

After:

> When an inherited widget changes, for example if the value of
Theme.of() changes, its dependent widgets are rebuilt. The framework
calls initState() only once for each State object and does not call it
again for those rebuilds, so a value that initState() reads from an
inherited widget is never updated when that inherited widget changes.

The existing test for this error (`initState() dependency on Inherited
asserts`) only checks that something was thrown, so the message itself
was untested; the new test covers it. `ExpectFail` now forwards the
caught error so a test can inspect it.

The issue also suggests adding a `_StateLifecycle` value between
`created` and `initialized`, set just before `initState()` is called. I
left that out. A `State` only gets its context after it is constructed
(`state._element` is assigned in the `StatefulElement` constructor after
`createState()` returns), so the only `State` code that runs with a
context before `initState()` completes is `initState()` itself, and a
new value would have no constructor case to separate. That is also why
the new message no longer mentions constructors; the general advice
about constructors stays in the
`BuildContext.dependOnInheritedWidgetOfExactType` docs.

Fixes flutter#105705

## 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.
- [x] I updated/added relevant in-code documentation (doc comments with
`///`).
- [x] If this PR introduces a new feature or capability, I created and
linked a website documentation issue or PR in [flutter/website] (or
verified none is needed).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] 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].

If this change needs to override an active code freeze, provide a
comment explaining why. The code freeze workflow can be overridden by
code reviewers. See pinned issues for any active code freezes with
guidance.

**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
[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
[flutter/website]: https://github.com/flutter/website
[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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CICD Run CI/CD framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Confusing error message : dependOnInheritedElement() was called before ${state.runtimeType}.initState()

4 participants