Skip to content
AgileLogics
6 min read

Exceptions and Error Handling

Prerequisites: Classes and objects

When something goes wrong while a program runs, Dart throws an exception. If nothing catches it, the program stops.

Real-world analogy: an exception is a fire alarm. catch is the plan for what to do when it goes off.

try, on, catch, finally

void main() {
  for (final input in ['42', 'abc']) {
    try {
      final n = int.parse(input);
      print('Parsed $n');
    } on FormatException catch (e) {
      print('Not a number: ${e.source}');
    } finally {
      print("Done with '$input'");
    }
  }
}
Parsed 42
Done with '42'
Not a number: abc
Done with 'abc'
  • on Type catches a specific kind of exception; catch (e) gives you the exception object. You can use either or both.
  • finally runs no matter what — for cleanup.

Throwing and custom exceptions

class InsufficientFundsException implements Exception {
  final double shortfall;
  InsufficientFundsException(this.shortfall);

  @override
  String toString() => 'Insufficient funds: short by $shortfall';
}

double withdraw(double balance, double amount) {
  if (amount <= 0) throw ArgumentError.value(amount, 'amount', 'must be positive');
  if (amount > balance) throw InsufficientFundsException(amount - balance);
  return balance - amount;
}

void main() {
  try {
    withdraw(50, 80);
  } on InsufficientFundsException catch (e) {
    print(e);
    print('Please deposit ${e.shortfall}');
  }

  try {
    withdraw(50, -5);
  } on ArgumentError catch (e) {
    print(e.message);
  }
}
Insufficient funds: short by 30.0
Please deposit 30.0
must be positive

Exception vs Error

Dart separates two kinds of problem:

  • Exception — an expected failure the program should handle: bad input, a missing file, a network timeout.
  • Error — a bug in the program: calling a method with invalid arguments (ArgumentError), an index out of range (RangeError), ! on null. These generally shouldn't be caught — fix the code instead.

Implement Exception for your own recoverable failures.

rethrow

Inside a catch, rethrow passes the same exception on after, say, logging it.

Common mistakes

  • A bare catch (e) everywhere, hiding bugs. Catch the specific types you can handle.
  • Using exceptions for normal outcomes. If "not found" is expected, returning null or a sealed result type is often clearer.

Practice

Write int parseAge(String text) that throws a FormatException with a helpful message if the text isn't a number or isn't between 0 and 150. Call it with '200' in a try/on block and print the message.

Show solution
int parseAge(String text) {
  final age = int.tryParse(text);
  if (age == null) throw FormatException("'$text' is not a number");
  if (age < 0 || age > 150) throw FormatException('Age $age is out of range (0-150)');
  return age;
}

void main() {
  try {
    parseAge('200');
  } on FormatException catch (e) {
    print('Error: ${e.message}');
  }
}
Error: Age 200 is out of range (0-150)