Skip to content

avoid_throw_in_catch_block

v0.4.0 Warning Fix Control Flow

Warns when a throw expression is used inside a catch block. Throwing a new exception (or re-throwing the caught one with throw e) discards the original stack trace, making debugging significantly harder. Use rethrow or Error.throwWithStackTrace() instead.

When you use throw inside a catch block, the original stack trace is lost. This means error reports and logs will point to the catch block instead of the actual source of the error. Using rethrow preserves the full stack trace, and Error.throwWithStackTrace() lets you throw a different exception while keeping the original stack trace attached.

See also: Exceptions | Dart lint: throw_in_finally | Dart lint: only_throw_errors

void bad() {
// throw loses original stack trace
try {
networkDataProvider();
} on Object {
throw RepositoryException();
}
// throw with caught exception still loses stack trace
try {
networkDataProvider();
} catch (e) {
throw e;
}
// throw with logic before it
try {
networkDataProvider();
} catch (e) {
print(e);
throw RepositoryException('failed');
}
}
void good() {
// Use Error.throwWithStackTrace to preserve the stack trace
try {
networkDataProvider();
} catch (_, stack) {
Error.throwWithStackTrace(RepositoryException(), stack);
}
// Use rethrow to re-throw the original exception
try {
networkDataProvider();
} catch (e) {
print(e);
rethrow;
}
// Throw inside a closure is fine — it's not in the catch scope
try {
networkDataProvider();
} catch (e) {
final callback = () {
throw RepositoryException();
};
callback();
}
}

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

To turn it off:

many_lints.yaml
rules:
avoid_throw_in_catch_block: false

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