Skip to content

avoid_incomplete_copy_with

v0.4.0 Warning Fix Collection & Type

Flags a copyWith whose parameters do not cover every parameter of the class’s unnamed constructor. The diagnostic names the missing ones, and the quick fix adds them.

This is what adding a field looks like when copyWith is not updated with it. Nothing breaks at the definition; the loss shows up at every call site, silently:

class Filters {
const Filters({
required this.query,
required this.category,
required this.inStockOnly,
});
final String query;
final String category;
final bool inStockOnly;
Filters copyWith({String? query, String? category}) {
return Filters(
query: query ?? this.query,
category: category ?? this.category,
inStockOnly: inStockOnly,
);
}
}

filters.copyWith(inStockOnly: true) does not compile, so the caller writes the whole constructor out by hand — or, worse, drops the toggle.

class Filters {
const Filters({
required this.query,
required this.category,
required this.inStockOnly,
});
final String query;
final String category;
final bool inStockOnly;
Filters copyWith({String? query, String? category, bool? inStockOnly}) {
return Filters(
query: query ?? this.query,
category: category ?? this.category,
inStockOnly: inStockOnly ?? this.inStockOnly,
);
}
}

The rule never asks you to add one — it only keeps an existing copyWith in step with the constructor:

// No warning: nothing to keep in sync
class Coordinates {
const Coordinates({required this.lat, required this.lon});
final double lat;
final double lon;
}

Only the unnamed constructor is compared. A class whose primary constructor is named — const Filters.initial({...}) — is not checked, since the rule finds no default constructor to compare against.

Parameters are matched by name only. A copyWith that declares the right names but ignores one in its body is not reported; the check is on the signature.

Nullable fields need a sentinel, and the rule does not know that. Adding String? note to copyWith makes copyWith(note: null) indistinguishable from “leave it alone”. The rule asks for the parameter; choosing a sentinel or a wrapper to express “set to null” is yours.

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

many_lints.yaml
rules:
avoid_incomplete_copy_with: true

To turn it off again:

many_lints.yaml
rules:
avoid_incomplete_copy_with: false

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