Skip to content

avoid_unnecessary_return

v1.0.0 Warning Control Flow

This rule flags a bare return; written as the last statement of a function that returns nothing. Control leaves the function whether it is there or not, but return reads as an early exit, so a reader stops to look for what is being skipped and finds the closing brace.

It is usually left behind by a change that moved or deleted the statements it once guarded.

class Order {
bool get isCancelled => false;
}
void send(Order order) {}
void process(Order order) {
send(order);
return;
}

Future<void> counts the same — an async function with nothing left to run:

Future<void> flush(List<String> pending) async {
await Future<void>.delayed(Duration.zero);
pending.clear();
return;
}

Drop the statement:

class Order {
bool get isCancelled => false;
}
void send(Order order) {}
void process(Order order) {
send(order);
}

An early return; that genuinely skips later statements is doing real work, and stays:

class Order {
bool get isCancelled => false;
}
void send(Order order) {}
void process(Order order) {
if (order.isCancelled) return;
send(order);
}

Only a return with no value is reported, and only when the return type is written as void or Future<void>.

An omitted return type is not treated as void — it means dynamic, where return; may be deliberate. So this is not reported:

process(List<String> pending) {
pending.clear();
return;
}

A bare closure is skipped too, for the same reason: its return type would have to be inferred.

This rule is in the opinionated preset.

To disable this rule:

many_lints.yaml
rules:
avoid_unnecessary_return: false

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