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 needs a seed, not a guard
Section titled “reduce needs a seed, not a guard”reduce throws for the same reason, but the fix is usually fold — a seed value makes the empty case meaningful instead of exceptional:
// Don'tint totalCents(List<int> amounts) { return amounts.reduce((a, b) => a + b);}// Do — an empty basket costs zeroint totalCents(List<int> amounts) { return amounts.fold(0, (a, b) => a + b);}Known limitations
Section titled “Known limitations”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(...).firsthas 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 callingfirstOrNull/lastOrNull/singleOrNullon it, counts too. This over-accepts on purpose. - A collection literal with elements (
[1, 2, 3].first) is treated as provably non-empty. singleWhereis excluded: it throws when no element matches, which an emptiness check would not prevent.
Configuration
Section titled “Configuration”This rule is in the opinionated preset, so it is on with
preset: opinionated, or by name:
rules: avoid_unsafe_collection_methods: trueTo turn it off again:
rules: avoid_unsafe_collection_methods: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_accessing_collections_by_constant_index— Avoid accessing a collection by a constant index inside a loop.prefer_safe_collection_access— list.first throws where list.head returns None.avoid_collection_methods_with_unrelated_types— Avoid calling collection methods with arguments whose types are unrelated to the collection’s type parameter.avoid_collection_equality_checks— Avoid comparing collections with == or != as it checks reference equality, not contents.