Skip to content

avoid_duplicate_collection_elements

v0.8.0WarningFixConfigurableCollection Type

This rule is in the pedantic preset.

Flags a list literal that contains the same element twice, and a spread or if element repeated in any literal. The quick fix removes the duplicate, keeping the first occurrence.

A repeated constant in a hand-written list is almost always a typo for a third value — nothing fails, the list just carries the entry twice:

enum Permission { read, write, delete }
const defaultPermissions = <Permission>[
Permission.read,
Permission.write,
Permission.read,
];
enum Permission { read, write, delete }
const defaultPermissions = <Permission>[
Permission.read,
Permission.write,
Permission.delete,
];

Spreading the same source twice either duplicates every value or is dead weight. This is the shape a merge conflict resolution leaves behind:

// Don't
final visible = [...pinnedItems, ...pinnedItems, ...recentItems];
// Do
final visible = [...pinnedItems, ...recentItems];

Spreads are checked inside sets and maps too, since the analyzer does not catch those:

// Don't
final allFlags = {...baseFlags, ...baseFlags};
// Do
final allFlags = {...baseFlags, ...overrideFlags};

Two identical if elements guard on the same condition and emit the same value — usually the second was meant to test the other branch:

// Don't
final rows = [
if (isAdmin) 'Manage users',
if (isAdmin) 'Manage users',
];
// Do
final rows = [
if (isAdmin) 'Manage users',
if (!isAdmin) 'Request access',
];

Padding lists and gradient stops legitimately repeat plain values. ignore_literals: true exempts them while still reporting a duplicated identifier or property access:

rules:
avoid_duplicate_collection_elements:
ignore_literals: true
// Accepted — plain literals
const padding = [0, 0, 0, 0];
// Still reported — a repeated named constant
const sizes = [Spacing.small, Spacing.small];

Only stable elements are compared. Elements are matched by source text, which is sound only for a literal, an identifier, or a property access. A constructor call is never compared, so [Locale('en'), Locale('en')] is not reported — nor is [next(), next()], since two calls may legitimately return different values. The same holds for spreads: [...fetch(), ...fetch()] is left alone.

Plain values in sets and maps are out of scope. The analyzer already reports duplicate set elements and duplicate map keys natively, so covering them here would double-report. Only spreads and if elements are checked in those literals.

This rule appears only in the pedantic preset because repeated values and actions are common in fixtures, ordered scenarios, gradients and other intentionally positional lists.

Enable it by name:

many_lints.yaml
rules:
avoid_duplicate_collection_elements: true

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

analysis_options.yaml
many_lints:
rules:
avoid_duplicate_collection_elements:
ignore_literals: true
Option Type Default Description
ignore_literals bool false Skip repeated literals ([0, 0, 0]), still reporting duplicated identifiers and property accesses