avoid_late_final_reassignment
v1.0.0 Warning Resource Management
This rule flags a late final field assigned more than once on the same straight-line path.
This rule is in the core preset.
Why use this rule
Section titled “Why use this rule”late final promises one assignment, and Dart enforces it — but at run time, by throwing LateInitializationError on the second write. A second assignment the analyzer can see on one path is therefore a guaranteed crash, not a possibility, and it is worth catching before the code runs.
See also: late variables
Assigning a provisional value and then refining it. The second line throws:
class Session { late final String token;
void start(String value) { token = value; token = value.trim(); // throws LateInitializationError }}Compute the final value first, then assign once:
class Session { late final String token;
void start(String value) { token = value.trim(); }}Branching is the intended use
Section titled “Branching is the intended use”Two writes in opposite arms of an if are exactly what late final is for — only one of them ever runs, so this is not reported:
class Session { late final String token;
void start({required bool isGuest}) { if (isGuest) { token = 'guest'; } else { token = _generate(); } }
String _generate() => 'real';}The same holds for a switch, and for an early return:
class Session { late final String token;
void start(String? cached) { if (cached != null) { token = cached; return; } token = _generate(); }
String _generate() => 'real';}Known limitations
Section titled “Known limitations”Only writes in the same block are compared, and the rule does not follow branches. That is what makes the branching examples above pass — but it also means a genuine double write split across a branch boundary is missed:
void start(String value) { if (value.isNotEmpty) { token = value; // not reported } token = value.trim(); // throws at run time when the branch above ran}Only fields are checked. A late final local with the same defect is left to the analyzer, which already flags it at compile time.
Only a plain = counts; a compound assignment to a late final does not compile in the first place.
Turning this rule off
Section titled “Turning this rule off”To disable this rule:
rules: avoid_late_final_reassignment: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”always_remove_listener— Ensure every addListener() has a matching removeListener() in dispose().avoid_unassigned_stream_subscriptions— Ensure stream subscriptions are assigned to a variable for proper cancellation.avoid_unremovable_callbacks_in_listeners— Don’t pass an inline closure to addListener.dispose_fields— Ensure State fields with disposal methods are cleaned up in dispose().