only-throw-errors

Same as only_throw_errors in Dart lints

Group
Style
Path
lint/style/only-throw-errors
Default
On (recommended)
Origin
Dart lints
Rule
305 of 512
recommended

Only throw instances of classes that extend Exception or Error.

Throwing arbitrary objects breaks on Exception / on Error handlers and loses the conventions tooling relies on:

throw 'Something went wrong'; // BAD
throw FormatException('Something went wrong'); // GOOD

Literals are always reported. Other thrown values are reported only when their resolved type provably implements neither Exception nor Error; dynamic, Never, and anything unresolved stay silent. Function and record values cannot implement either throwable interface and are reported. Resolved types include promotions on the current control-flow path, and extension types are checked through their representation types.

Invalid

example.dartdart
class NotAnException {}

class Wrapper<T> {
  T value;
  Wrapper(this.value);
}

void throwsString() {
  throw 'Something went wrong';
}

void throwsInt() {
  throw 42;
}

void throwsList() {
  throw ['a', 'b'];
}

void throwsInterpolation(int code) {
  throw 'code $code';
}

void throwsCustom() {
  throw NotAnException();
}

int throwsInExpression(int? value) => value ?? (throw 'missing');

void throwsLocal() {
  final error = NotAnException();
  throw error;
}

void throwsObject(Object error) {
  throw error;
}

void throwsFunction(void Function() callback) {
  throw callback;
}

void throwsRecord((int, String) value) {
  throw value;
}

extension type ObjectValue(Object value) implements Object {}

void throwsObjectValue() {
  throw ObjectValue(Object());
}

// Declare the getter locally: this corpus runs without SDK member signatures.
// The inherited List.first cases live in the external-source inference tests.
class CollectedErrors {
  final _values = <Object>[];
  Object get first => _values.first;
  void add(Object error) => _values.add(error);
}

void throwsFirst(CollectedErrors errors) {
  throw errors.first;
}

void throwsCollectedErrors() {
  final errors = CollectedErrors();
  try {
    throw Error();
  } catch (error) {
    errors.add(error);
  }
  throw errors.first;
}
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
8void throwsString() {
9 throw 'Something went wrong';
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
12void throwsInt() {
13 throw 42;
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
16void throwsList() {
17 throw ['a', 'b'];
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
20void throwsInterpolation(int code) {
21 throw 'code $code';
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
24void throwsCustom() {
25 throw NotAnException();
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
27
28int throwsInExpression(int? value) => value ?? (throw 'missing');
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
31 final error = NotAnException();
32 throw error;
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
35void throwsObject(Object error) {
36 throw error;
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
39void throwsFunction(void Function() callback) {
40 throw callback;
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
43void throwsRecord((int, String) value) {
44 throw value;
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
49void throwsObjectValue() {
50 throw ObjectValue(Object());
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
61void throwsFirst(CollectedErrors errors) {
62 throw errors.first;
Don't create and throw instances of classes that don't extend `Exception` or `Error`.
71 }
72 throw errors.first;

Valid

example.dartdart
class MyException implements Exception {}

class MyError extends Error {}

void throwsException() {
  throw Exception('Something went wrong');
}

void throwsFormatException() {
  throw FormatException('bad input');
}

void throwsStateError() {
  throw StateError('bad state');
}

void throwsCustomException() {
  throw MyException();
}

void throwsCustomError() {
  throw MyError();
}

void throwsDynamic(dynamic value) {
  throw value;
}

void throwsBounded<T extends Exception>(T error) {
  throw error;
}

Never fail() => throw UnsupportedError('nope');

int throwsInExpression(int? value) => value ?? (throw ArgumentError('missing'));

// Interface checks use the representation, even when only Object is implemented.
extension type ErrorValue(Error value) implements Object {}
extension type ExceptionValue(Exception value) implements Object {}
extension type NestedErrorValue(ErrorValue value) implements Object {}
extension type GenericErrorValue<T extends Error>(T value) implements Object {}

void throwsErrorValue() {
  throw ErrorValue(Error());
}

void throwsExceptionValue() {
  throw ExceptionValue(Exception());
}

void throwsNestedErrorValue() {
  throw NestedErrorValue(ErrorValue(Error()));
}

void throwsGenericErrorValue() {
  throw GenericErrorValue<StateError>(StateError('bad state'));
}

void throwsBoundedErrorValue<T extends ErrorValue>(T value) {
  throw value;
}

Configure only-throw-errors

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "style": {
        "only-throw-errors": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/style/only-throw-errors: <reason>