Skip to content

avoid_only_rethrow

v0.4.0WarningFixConfigurableControl Flow

Flags a catch clause whose entire body is rethrow;. It catches the exception only to put it straight back, which is what would have happened with no try at all.

See also: Exceptions | Dart lint: use_rethrow_when_possible

This usually survives a refactor: the logging that justified the catch was moved elsewhere, and the empty shell stayed:

Future<Order> loadOrder(String id) async {
try {
return await fetchOrder(id);
} catch (e) {
rethrow;
}
}
Future<Order> fetchOrder(String id) async => Order();
class Order {}

Delete the try — the behaviour is identical:

Future<Order> loadOrder(String id) async {
return await fetchOrder(id);
}
Future<Order> fetchOrder(String id) async => Order();
class Order {}

That is what the quick fix does when the offending clause is the only one and there is no finally. Otherwise it removes just that clause and leaves the rest of the try in place.

A clause that does something before rethrowing is never reported:

Future<Order> loadOrder(String id) async {
try {
return await fetchOrder(id);
} catch (e, s) {
log.warning('order $id failed to load', e, s);
rethrow;
}
}
Future<Order> fetchOrder(String id) async => Order();
class Order {}
abstract final class log {
static void warning(String message, Object error, StackTrace stack) {}
}

So is one that rethrows conditionally, since it handles some cases and forwards the rest:

void parse(String source) {
try {
decode(source);
} catch (e) {
if (e is FormatException) {
useDefaults();
return;
}
rethrow;
}
}
void decode(String source) {}
void useDefaults() {}

A typed clause is still reported by default

Section titled “A typed clause is still reported by default”

on Exception { rethrow; } looks narrower but behaves the same — the exception propagates either way:

void demo(String source) {
// Don't
try {
decode(source);
} on FormatException {
rethrow;
}
}
void decode(String source) {}

There is one case where the typed form is not redundant: a try with several clauses, where one handles and another only forwards. If your codebase writes that deliberately, exempt typed clauses:

analysis_options.yaml
many_lints:
rules:
avoid_only_rethrow:
ignore_typed_catches: true

With that set, on FormatException { rethrow; } is accepted and the untyped catch (e) { rethrow; } still reports.

The body must be exactly one statement, and that statement must be rethrow;. A body with a comment above the rethrow is still one statement and is still reported.

Each clause is judged on its own, so a try with one real handler and one bare-rethrow clause reports the second — turn on ignore_typed_catches if that shape is intentional in your project.

Option Type Default Description
ignore_typed_catches bool false Only report untyped catch (e) clauses, leaving on SomeError { rethrow; } alone

This rule is in the recommended preset, so it is on with preset: recommended or preset: opinionated. Add it to preset: core with avoid_only_rethrow: true.

To turn it off:

many_lints.yaml
rules:
avoid_only_rethrow: false

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