Skip to content

avoid_nested_conditional_expressions

v1.0.0WarningConfigurableControl Flow

Flags a conditional expression (? :) nested inside another one. a ? b : (c ? d : e) packs a decision tree onto one line and the reader has to track which ? each : belongs to.

This rule is in the opinionated preset.

With max_depth: 1, the default, one nesting level is already over the limit:

String label(int score) =>
score > 100 ? 'high' : (score > 50 ? 'medium' : 'low');

A switch expression lines the branches up:

String label(int score) => switch (score) {
> 100 => 'high',
> 50 => 'medium',
_ => 'low',
};

A switch needs a single subject. When the tests are unrelated, early returns are the way out:

// Don't
String shippingLabel(bool express, bool international, double weightKg) =>
express
? (international ? 'Express international' : 'Express domestic')
: 'Standard';
// Do
String shippingLabel(bool express, bool international, double weightKg) {
if (!express) return 'Standard';
if (international) return 'Express international';
return 'Express domestic';
}

Nesting in the then-branch counts the same

Section titled “Nesting in the then-branch counts the same”

Depth is measured down both branches and the deeper one wins, so a conditional in the then position is reported just as readily as one in the else:

// Don't
String tier(bool member, int years) =>
member ? (years > 5 ? 'gold' : 'silver') : 'guest';

Some codebases accept a single nesting and want only the deeper ones flagged. With max_depth: 2, the two-level example above passes and a third level reports:

analysis_options.yaml
many_lints:
rules:
avoid_nested_conditional_expressions:
enabled: true
max_depth: 2
// Accepted at max_depth: 2
String tier(bool member, int years) =>
member ? (years > 5 ? 'gold' : 'silver') : 'guest';
// Still reported — three levels
String band(int n) => n > 100 ? 'a' : (n > 50 ? 'b' : (n > 10 ? 'c' : 'd'));

The diagnostic lands on the outermost conditional of a chain, so one nested tree gives one report rather than one per level. The message names the measured depth and the configured limit.

Nesting is only followed through the ? and : branches, not through everything written inside them. A conditional passed as an argument — outer ? f(a ? b : c) : d — starts its own count, so each is measured separately and neither may reach the limit.

The condition itself is not counted. (a ? b : c) ? d : e is depth 1.

There is no quick fix: whether the right replacement is a switch, early returns, or a named helper depends on what the branches mean.

Option Type Default Description
max_depth int 1 Maximum allowed conditional-expression nesting depth

To disable this rule:

many_lints.yaml
rules:
avoid_nested_conditional_expressions: false

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