Yeda AI Tips · #108

Español

Check context.mounted After Every await

Your Flutter app crashes after a slow network call. One line fixes it. The pattern is always the same: a button handler awaits a request, the user navigates away while it's in flight, and when the response finally lands your code touches a BuildContext whose widget no longer exists. On a fast connection you never see it; on a 3-second cellular round trip it's a crash report.

Why the context dies

Every widget's BuildContext is only valid while that widget is mounted in the tree. An await is an async gap — between the line before it and the line after it, anything can happen: the user pops the route, the parent rebuilds without this child, the app backgrounds. If the widget was disposed during the gap, calling Navigator.of(context), ScaffoldMessenger.of(context), or setState afterwards hits a defunct element. The framework's own docs are blunt about it: accessing properties of a BuildContext or calling methods on it "is only valid while mounted is true."

The one-line guard

Since Flutter 3.7, BuildContext itself exposes a mounted property, so the fix is a single check between the await and the first use of the context:

Future<void> _onSave(BuildContext context) async {
  await repository.save(item);        // async gap — anything can happen here
  if (!context.mounted) return;       // the guard
  Navigator.of(context).pop();        // now safe
  ScaffoldMessenger.of(context)
      .showSnackBar(const SnackBar(content: Text('Saved')));
}

Inside a State subclass, use the state's own mounted instead — same idea, no context parameter needed:

final data = await api.fetch();
if (!mounted) return;
setState(() => _data = data);

The guard goes after every await that precedes a context use — two awaits in a row means the first check is stale by the time the second completes.

Rules of thumb

SituationGuard
Plain function receiving a BuildContextif (!context.mounted) return; after each await
Inside State<T> (has its own context)if (!mounted) return; after each await
Multiple awaits before the context useCheck after the last await, not just the first
Context captured before the await (e.g. final nav = Navigator.of(context) first)Capturing Navigator/ScaffoldMessenger before the gap avoids the lookup, but still check mounted before UI work
No context use after the awaitNo guard needed

Let the linter catch it for you

You don't have to rely on discipline. The Dart linter rule use_build_context_synchronously flags exactly this bug — a BuildContext referenced across an async gap without a mounted check. It ships stable and is part of the recommended flutter_lints set that new Flutter projects (2.3.0+) include by default via analysis_options.yaml:

include: package:flutter_lints/flutter.yaml

If your CI runs flutter analyze, this class of crash becomes a build failure instead of a production incident.

Power-user notes

Resources

Building an AI feature? Yeda AI designs, audits, and ships production LLM systems.

Talk to us · Read the blog