avoid_mounted_in_setstate
Warns when mounted or context.mounted is checked inside a setState callback. If the widget has been disposed, setState itself throws an exception before the callback ever runs, making any mounted check inside it useless.
Why use this rule
Section titled “Why use this rule”A common misconception is that checking mounted inside setState protects against calling setState on a disposed widget. In reality, setState validates the state object immediately when called — if the widget is unmounted, it throws before executing the callback. The mounted check must happen before the setState call, not inside it.
See also: State.mounted | State.setState
An async handler that guards inside the callback. The guard never runs — setState has already thrown by then — and the state still gets assigned when the widget survives, so the code looks like it works:
class _ProfilePageState extends State<ProfilePage> { String _name = '';
Future<void> _load() async { final name = await fetchName();
setState(() { if (mounted) { _name = name; } }); }
@override Widget build(BuildContext context) => Text(_name);}context.mounted inside the callback is the same mistake:
class _ProfilePageState extends State<ProfilePage> { String _name = '';
Future<void> _load() async { final name = await fetchName();
setState(() { if (context.mounted) { _name = name; } }); }
@override Widget build(BuildContext context) => Text(_name);}Guard before the call, and let the callback do nothing but mutate:
class _ProfilePageState extends State<ProfilePage> { String _name = '';
Future<void> _load() async { final name = await fetchName(); if (!mounted) return;
setState(() { _name = name; }); }
@override Widget build(BuildContext context) => Text(_name);}When the value is needed for something that also uses the context — a snackbar,
a route — context.mounted reads better, and it belongs in the same place:
class _ProfilePageState extends State<ProfilePage> { String _name = '';
Future<void> _load() async { final name = await fetchName(); if (!context.mounted) return;
setState(() { _name = name; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Welcome, $name')), ); }
@override Widget build(BuildContext context) => Text(_name);}Known limitations
Section titled “Known limitations”The whole callback is searched, including nested closures. A mounted read
inside a closure that setState merely stores for later — rare, but legal — is
reported too.
Only an inline callback is inspected. setState(_applyName) passes a method
reference, and the rule does not follow it.
Turning this rule off
Section titled “Turning this rule off”This rule is in the recommended preset, so it is on with
preset: recommended or preset: opinionated. Add it to preset: core with
avoid_mounted_in_setstate: true.
To turn it off:
rules: avoid_mounted_in_setstate: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Options
Section titled “Options”Projects with a state abstraction that does not extend Flutter’s State can
opt that base class into this rule:
many_lints: rules: avoid_mounted_in_setstate: state_base_classes: [AppState]rules: avoid_mounted_in_setstate: state_base_classes: [AppState]| Option | Type | Default | Description |
|---|---|---|---|
state_base_classes |
list of strings | [] |
Additional non-State base classes whose subclasses should be treated as state classes |
Related rules
Section titled “Related rules”avoid_empty_setstate— Don’t call setState with an empty callback.avoid_unnecessary_setstate— Detect unnecessary setState calls in lifecycle methods.avoid_inherited_widget_in_initstate— Don’t look up inherited widgets inside initState.avoid_late_context— Don’t read BuildContext in a late field initializer.