prefer_typed_exceptions
Warns when a throw does not name a type a caller could catch selectively — a
bare Exception('...'), a raw string, or any object that is neither Error
nor Exception.
Why use this rule
Section titled “Why use this rule”throw Exception('upload failed') cannot be caught by kind. Every catch
downstream either swallows everything or re-inspects the message string, and
message matching breaks the moment somebody improves the wording — silently,
because the catch still compiles and still runs.
Three things are reported:
throw Exception(...)andthrow Error(...)— the base types, which say nothing.throw 'a string'(or any non-throwable value).throw SomeClass(...)whereSomeClassimplements neitherErrornorException.
An SDK type from the allow list is accepted, and so is any project type that
implements Exception or Error.
Dart’s own only_throw_errors
covers the adjacent case — throwing a bare string — but is satisfied by
Exception(...), which is where most of the damage is. This rule covers both,
so enabling it alone is sufficient.
See also: Dart lint: only_throw_errors | Effective Dart: error handling
class Failure { const Failure(this.message);
final String message;}
void uploadArtifact() { // Nothing downstream can catch just this failure. throw Exception('upload failed');}
void uploadRaw() { // Not even an Exception. throw 'upload failed';}
void uploadDomain() { // A domain class that forgot `implements Exception` is just as opaque: // `on Failure` does not compile against a non-throwable. throw const Failure('upload failed');}Give each failure a type, and the boundary can branch on it:
class UploadFailure implements Exception { const UploadFailure(this.path);
final String path;}
class AuthFailure implements Exception { const AuthFailure();}
void uploadArtifact(String path) { throw UploadFailure(path);}Future<void> run(String path) async { try { await upload(path); } on AuthFailure { exitCode = 3; } on UploadFailure catch (failure) { stderr.writeln('could not upload ${failure.path}'); exitCode = 4; }}SDK types whose own name already identifies the failure are accepted as they are:
void configure(int port) { if (port <= 0) { throw ArgumentError.value(port, 'port', 'must be positive'); }}Turning this rule off
Section titled “Turning this rule off”This rule is in the recommended preset, so it is on with
preset: recommended, preset: opinionated or preset: pedantic. Add it to
preset: core with prefer_typed_exceptions: true.
To turn it off:
rules: prefer_typed_exceptions: falseTo keep the rule on but skip certain paths — tests often throw freely — use
per-rule exclude.
Options
Section titled “Options”Both options name dart:core types only. A type from any other library —
TimeoutException, or one of your own — is judged by whether it implements
Exception or Error, which no list can override.
additional_allow
Section titled “additional_allow”Extends the default list. Use it to accept a core type the defaults leave out:
many_lints: rules: prefer_typed_exceptions: additional_allow: - OutOfMemoryErrorrules: prefer_typed_exceptions: additional_allow: - OutOfMemoryErrorReplaces the default list outright. Use it to narrow the defaults — a project
that wants every failure named, ArgumentError included, can empty the list:
rules: prefer_typed_exceptions: allow: []Prefer additional_allow for anything else: a restated default list silently
rots when a later version of this package adds a name.
| Option | Type | Default | Description |
|---|---|---|---|
allow |
list of strings | see below | dart:core types specific enough to throw directly. Replaces the default list |
additional_allow |
list of strings | [] |
Adds to whichever list won, so you can extend the defaults without restating them |
The default allow list is:
ArgumentError, AssertionError, ConcurrentModificationError,
FormatException, IndexError, RangeError, StateError,
UnimplementedError, UnsupportedError.
Each of these is already as catchable as a hand-written class would be, so wrapping one adds a type without adding information.
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.