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. That break is
silent: the catch still compiles and still runs, it just stops matching.
This is concrete for anything that maps failures onto behaviour — a CLI choosing an exit code, a client deciding whether to retry, a UI choosing between “check your connection” and “that file is not valid”. None of those questions can be answered about a value whose only distinguishing feature is prose.
How this differs from the SDK’s only_throw_errors
Section titled “How this differs from the SDK’s only_throw_errors”Dart’s only_throw_errors
covers the adjacent case — throwing something that is neither Error nor
Exception, like a bare string — but is satisfied by Exception(...), which
is where most of the real damage is. This rule covers both, so enabling it
alone is sufficient.
See also: Dart lint: only_throw_errors | Effective Dart: error handling
void bad() { // Nothing downstream can catch just this failure. throw Exception('upload failed');
// Not even an Exception. throw 'upload failed';
// A domain object that forgot to implement Exception is just as opaque. throw Failure('upload failed');}class UploadFailure implements Exception { const UploadFailure(this.message);
final String message;}
void good() { // A caller can catch exactly this, and nothing else. throw const UploadFailure('upload failed');}
void alsoGood(int port) { // SDK types whose own name identifies the failure are allowed by default. throw ArgumentError.value(port, 'port', 'must be positive');}Catching then becomes precise, which is what makes an error taxonomy testable:
try { await upload(artifact);} on AuthFailure { exitCode = 3;} on UploadFailure { exitCode = 4;}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”many_lints: rules: prefer_typed_exceptions: additional_allow: - TimeoutExceptionrules: prefer_typed_exceptions: additional_allow: - TimeoutException| Option | Type | Default | Description |
|---|---|---|---|
allow |
list of strings | see below | SDK 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. Prefer additional_allow
over allow: a restated default list silently rots when a later version of
this package adds a name.
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.