Skip to content

no_magic_string

v1.0.0WarningConfigurableCode Quality

This rule flags the same string literal repeated without a name.

Unlike its numeric sibling, this rule reports only repetition — the case where a string is genuinely dangerous. A route path, a storage key or a header name written out at three call sites will eventually be changed at two of them, and the third failure is silent.

A single occurrence is left alone. It is usually a message or a label, and naming it moves the text away from the code that uses it for no gain.

This rule is in the pedantic preset: the threshold is a house style.

A storage key spelled out at each call site — rename it once and one of these is left behind:

class SessionCache {
final Map<String, String> _box = {};
String? read() => _box['auth.refresh_token'];
void write(String token) => _box['auth.refresh_token'] = token;
void clear() => _box.remove('auth.refresh_token');
}
const refreshTokenKey = 'auth.refresh_token';
class SessionCache {
final Map<String, String> _box = {};
String? read() => _box[refreshTokenKey];
void write(String token) => _box[refreshTokenKey] = token;
void clear() => _box.remove(refreshTokenKey);
}

The diagnostic appears at every occurrence rather than only the first: each one is separately editable, and showing one would hide the duplication the rule is about.

Exempting a wrapper that takes strings by design

Section titled “Exempting a wrapper that takes strings by design”

A translation or logging helper is called with a literal key everywhere on purpose. Name it rather than turning the rule off:

analysis_options.yaml
many_lints:
rules:
no_magic_string:
additional_ignored_invocations: [translate, featureFlag]
String translate(String key) => key;
// Not reported under the configuration above.
final a = translate('cart.checkout');
final b = translate('cart.checkout');
final c = translate('cart.checkout');

Three occurrences is the default. Wait for a fourth with:

many_lints.yaml
rules:
no_magic_string:
min_occurrences: 4

Two occurrences never report at the default min_occurrences: 3.

Strings shorter than min_length (3) are ignored — separators and punctuation rather than identifiers.

A literal that initialises a declaration is exempt, along with anything inside a const declaration, an enum, or an annotation. That is the shape the rule asks you to move towards.

Tests are exempt by default, where a repeated fixture string is the test data. Set ignore_tests: false to include them.

analysis_options.yaml
many_lints:
rules:
no_magic_string:
min_occurrences: 3
min_length: 3
additional_ignored_invocations: [translate]
ignore_tests: true
Option Type Default Description
min_occurrences int 3 How many times a string must repeat before it reports
min_length int 3 Shortest string considered; below this it is punctuation
ignored_invocations list of strings [] Constructors and methods whose string arguments never report
additional_ignored_invocations list of strings [] Names to add without replacing ignored_invocations
ignore_tests bool true Skip files under test/

To disable this rule:

many_lints.yaml
rules:
no_magic_string: false

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