# Flutter: “Looking up a deactivated widget’s ancestor is unsafe”

> Flutter says looking up a deactivated widget’s ancestor is unsafe: code used a BuildContext after its widget left the screen. Check mounted first.

Canonical: https://app369.com/fix/flutter-looking-up-a-deactivated-widgets-ancestor-is-unsafe/
Last updated: 2026-11-08

The app throws Looking up a deactivated widget's ancestor is unsafe, often right after a dialog closes, a screen pops or an async call returns. The code used a BuildContext whose widget has already left the screen, to call Navigator.of, ScaffoldMessenger.of, Theme.of or a Provider lookup. That context can no longer find the widgets above it.

**Short answer**

Find the .of(context) call on the first stack trace line in your own code. If it runs after an await, add if (!context.mounted) return; right before it (or if (!mounted) return; inside a State). If it runs in dispose(), look the object up in didChangeDependencies, keep it in a field, and use the field in dispose. If it runs after Navigator.pop, use the navigator or messenger you looked up before the pop. The analyzer lint use_build_context_synchronously flags the after-await case.

## **Where the stale context comes from, and the fix**

1. 01 ### **A context used after an await**
  > “If a BuildContext is used across an asynchronous gap (i.e. after performing an asynchronous operation), consider checking mounted to determine whether the context is still valid before interacting with it” [**Flutter, BuildContext class**](https://api.flutter.dev/flutter/widgets/BuildContext-class.html) The user leaves the screen while a network call or a dialog is running. When the await returns, Navigator.of(context) or ScaffoldMessenger.of(context) runs on a widget that is gone. Check mounted after every await that is followed by a context call.```
onPressed: () async {
  await saveProfile();
  if (!context.mounted) return;
  Navigator.of(context).pop();
},
```
2. 02 ### **An .of(context) call in dispose()**
  > “To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.” [**Flutter, Flutter framework source (the error’s hint)**](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart) By the time dispose() runs, the widget is out of the tree, so ScaffoldMessenger.of(context), Provider.of(context) and similar lookups fail there. Look the object up in didChangeDependencies, keep it in a field, and use the field in dispose. .of(context) calls dependOnInheritedWidgetOfExactType() for you, which is why the error’s own hint names it.```
late ScaffoldMessengerState _messenger;

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  _messenger = ScaffoldMessenger.of(context);
}

@override
void dispose() {
  _messenger.hideCurrentSnackBar();
  super.dispose();
}
```
3. 03 ### **A context kept in a field or passed to a service**
  > “Avoid storing instances of BuildContexts because they may become invalid if the widget they are associated with is unmounted from the widget tree.” [**Flutter, BuildContext class**](https://api.flutter.dev/flutter/widgets/BuildContext-class.html) A BuildContext stored in a variable, a singleton or a long-lived callback outlives its widget. When the code uses it later, the widget may be gone. Pass the context in at the moment it is needed, or use a navigatorKey or scaffoldMessengerKey for app-wide navigation and snackbars.
4. 04 ### **A timer, stream or listener that outlives the screen**
  > “After the framework calls dispose, the State object is considered unmounted and the mounted property is false. It is an error to call setState at this point.” [**Flutter, State.dispose**](https://api.flutter.dev/flutter/widgets/State/dispose.html) A Timer, StreamSubscription or listener keeps firing after the screen closes and calls setState or an .of(context) lookup. Cancel it in dispose, and check mounted at the top of the callback.

Checked against the vendor’s docs on November 8, 2026: [Flutter API: BuildContext class](https://api.flutter.dev/flutter/widgets/BuildContext-class.html); [Flutter API: State.dispose](https://api.flutter.dev/flutter/widgets/State/dispose.html); [Flutter source: framework.dart (the error message and its hint)](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/widgets/framework.dart).

## **Rather hand it over?**

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

- [from $450**App Fix Ticket**One reproducible bug in an existing mobile or web app, diagnosed and fixed.**See scope and start**](https://app369.com/fixed-price/flutter-firebase-bug-fix/)
- [from $450**AI-Built App Rescue**A Lovable, Bolt or Cursor app checked end to end in 3 days, then its worst problems fixed at a fixed price.****No issues worth fixing, no charge.**** If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.**See scope and start**](https://app369.com/fixed-price/ai-app-rescue/)

Related: [**Flutter “setState() called during build”**](https://app369.com/fix/flutter-setstate-called-during-build/) · [**Flutter LateInitializationError**](https://app369.com/fix/flutter-lateinitializationerror-field-has-not-been-initialized/) · [**Flutter “Null check operator used on a null value”**](https://app369.com/fix/flutter-null-check-operator-used-on-a-null-value/) · [**Flutter “type 'Null' is not a subtype of type 'String'”**](https://app369.com/fix/flutter-type-null-is-not-a-subtype-of-type-string/)

Questions

## **More on this error**

<details>

<summary>**Which context should a dialog use? **+</summary>

Inside showDialog’s builder, name the parameter dialogContext and use it to close the dialog. Use the screen’s context for anything after the dialog closes, and check context.mounted first if there was an await in between.

</details>

<details>

<summary>**Is wrapping the call in try/catch a fix? **+</summary>

No. The call still does nothing useful, and the same stale context can fail somewhere else. Stop the call from running once the widget is gone.

</details>

<details>

<summary>**Can you fix it for me? **+</summary>

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

</details>

A different error?

## **Describe it and get a written quote**

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.

[**Describe your problem **→](https://app369.com/contact/) [**All fixes**](https://app369.com/fix/)