avoid_only_rethrow
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.
Or give the clause a reason to exist
Section titled “Or give the clause a reason to exist”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:
many_lints: rules: avoid_only_rethrow: ignore_typed_catches: truerules: avoid_only_rethrow: ignore_typed_catches: trueWith that set, on FormatException { rethrow; } is accepted and the untyped catch (e) { rethrow; } still reports.
Known limitations
Section titled “Known limitations”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.
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
ignore_typed_catches |
bool | false |
Only report untyped catch (e) clauses, leaving on SomeError { rethrow; } alone |
Turning this rule off
Section titled “Turning this rule off”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:
rules: avoid_only_rethrow: falseTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”avoid_cascade_after_if_null— Detect cascades after if-null operators without parentheses.avoid_collapsible_if— Merge nested if statements with &&.avoid_constant_conditions— Detect comparisons where both sides are constants.avoid_constant_switches— Detect switch statements on constant expressions.