Skip to content

avoid_unsafe_collection_methods

v0.8.0 Warning Collection Type

Flags first, last, single and reduce on a named collection that has no emptiness check anywhere in the enclosing function. All four throw a StateError on an empty iterable.

The list is non-empty in every test and every demo, so this ships and crashes on the first user whose account has no activity:

String latestActivityLabel(List<String> entries) {
return entries.last;
}

Because the throw comes from dart:core, the stack trace points at framework code rather than at the line that assumed a value was there.

Guard the access and say what happens when there is nothing:

String latestActivityLabel(List<String> entries) {
if (entries.isEmpty) return 'No activity yet';
return entries.last;
}

Or take the null-returning variant and handle the absence at the call site:

String latestActivityLabel(List<String> entries) {
return entries.lastOrNull ?? 'No activity yet';
}

firstOrNull, lastOrNull and singleOrNull come from package:collection.

reduce throws for the same reason, but the fix is usually fold — a seed value makes the empty case meaningful instead of exceptional:

// Don't
int totalCents(List<int> amounts) {
return amounts.reduce((a, b) => a + b);
}
// Do — an empty basket costs zero
int totalCents(List<int> amounts) {
return amounts.fold(0, (a, b) => a + b);
}

Detection is deliberately narrow, to keep false positives near zero:

  • Only a directly named receiver is checked — a local, parameter, or field. A chained expression like items.where(...).first has no name to match a guard against and is never reported.
  • Any emptiness check on that name anywhere in the function counts as a guard, even one in an unrelated branch. Reading .length, or calling firstOrNull/lastOrNull/singleOrNull on it, counts too. This over-accepts on purpose.
  • A collection literal with elements ([1, 2, 3].first) is treated as provably non-empty.
  • singleWhere is excluded: it throws when no element matches, which an emptiness check would not prevent.

This rule is in the opinionated preset, so it is on with preset: opinionated, or by name:

many_lints.yaml
rules:
avoid_unsafe_collection_methods: true

To turn it off again:

many_lints.yaml
rules:
avoid_unsafe_collection_methods: false

To keep the rule on but skip certain paths, use per-rule exclude.