exception error handling

All exceptions in Dart are unchecked exceptions. You don’t need to declare thrown types on functions, and catching errors is not mandatory.

There are two core categories:

  • Exception: Predictable business errors (invalid format, bad parameters, etc. Recommended to catch and handle).
  • Error: Fatal program failures (type mismatches, null pointer access, unimplemented methods, etc. Generally not caught).

Any non-null object can be thrown via throw. Standard projects should only throw subclasses of Exception/Error.

Uncaught exceptions terminate the current isolate and crash the entire application.

throw – Throwing Exceptions

1. Throw built-in system exceptions

void main() {
  // Format error
  throw FormatException("At least one data segment is required");
}
Code language: Dart (dart)
D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
FormatException: Error description
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:3:3)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

This snippet manually triggers a built-in exception with a custom message. You might wonder what purpose this serves, but throwing errors is critical for real-world logic. Take user registration as an example: we validate input formats. If input breaks the rules, we throw an error immediately to notify users and block malformed data from polluting our data layer.

2. Throwing arbitrary objects

Not recommended for production builds

void main() {
  throw "Custom error message text!";
}Code language: Dart (dart)

Execution output

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
Custom error message text!
#0      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:2:3)
#1      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#2      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

3. throw inside arrow functions (throw counts as an expression)

class Point {}
void distanceTo(Point other) => throw UnimplementedError("This method has not been implemented");

void main() {
  distanceTo(Point());
}
Code language: JavaScript (javascript)

try / on / catch – Catching Exceptions

Syntax Differences

  • on ExceptionType: Matches only the specified exception type; cannot access the exception instance.
  • catch(e): Catches all exceptions; variable e holds the exception instance.
  • catch(e, s): e = exception object, s = StackTrace call stack data.

1: Catch single specific exception with on


// Create custom exception implementing standard Exception
class OutOfLlamasException implements Exception {}

// Function that throws our custom error
void breedMoreLlamas() {
  throw OutOfLlamasException();
}

void buyMoreLlamas() {
  print("buyMoreLlamas function executed");
}

void main() {
  try {
    breedMoreLlamas(); // Execute risky logic
  } on OutOfLlamasException {
    buyMoreLlamas(); // Runs if OutOfLlamasException is caught
  }
}Code language: Dart (dart)

Execution output

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
buyMoreLlamas function executedCode language: JavaScript (javascript)
try  {
    // Code that may crash
} on ExceptionType {
   // Logic to run after catching the error
}Code language: Dart (dart)

try on is a dedicated syntax for type-specific exception capture.

2: Multi-layer sequential exception capture

More specific match branches run first

class OutOfLlamasException implements Exception {}

void breedMoreLlamas() {
  throw FormatException("Data format mismatch");
}

void main() {
  try {
    breedMoreLlamas();
  }
  // 1. Exact match for custom exception
  on OutOfLlamasException {
    print("Caught OutOfLlamasException error");
  }
  // 2. Catch all subclasses of Exception
  on Exception catch (e) {
    print("General business exception: $e");
  }
  // 3. Fallback catch for Errors and any other thrown objects
  catch (e) {
    print("Unknown critical error: $e");
  }
}
Code language: Dart (dart)

Output: General business exception: FormatException: Data format mismatch

We can use multiple on blocks to target distinct exception types, plus a final catch as universal fallback.

3: Capture exception and print full StackTrace

void main() {
  try {
    int a = null;
    print(a + 1);
  } catch (e, stack) {
    print("Exception message: $e");
    print("Full call stack trace:\n$stack");
  }
}
Code language: Dart (dart)

This code prints both the error message and the complete function call stack for debugging.

D:\dartdemo\firstdart>dart run
Building package executable...
Failed to build firstdart:firstdart:
bin/firstdart.dart:3:13: Error: A value of type 'Null' can't be assigned to a variable of type 'int'.
    int a = null;Code language: PHP (php)

rethrow

Handle partial logic then bubble the error upward

Purpose: Process part of the error logic inside the current function, then pass the exception to upstream caller code for further handling.

Sometimes we need to run recovery logic locally while also letting the parent caller receive the error for additional processing.

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // true cannot be incremented, triggers runtime error
  } catch (e) {
    print("Local handling inside misbehave: ${e.runtimeType}");
    rethrow; // Re-throw to outer try block
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print("Final handling inside main: ${e.runtimeType}");
  }
}
Code language: Dart (dart)

Execution flow:

Local handling inside misbehave: NoSuchMethodError
Final handling inside main: NoSuchMethodError
Code language: PHP (php)

The error gets processed both inside misbehave and the main entry point.

finally Block

Guaranteed to execute regardless of errors

Two common usage patterns:

  1. try + finally only: Errors are not caught; program crashes after running finally logic.
  2. try + catch + finally: Process error first, then run finally (standard for resource cleanup).

1: try + finally

void cleanLlamaStalls() => print("Clean up resources, guaranteed execution");
void breedMoreLlamas() => throw Exception("Runtime error occurred");

void main() {
  try {
    breedMoreLlamas();
  } finally {
    cleanLlamaStalls();
  }
}
Code language: Dart (dart)

The cleanup code runs, but the uncaught error still crashes the program afterward.

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Clean up resources, guaranteed execution
Unhandled exception:
Exception: Runtime error occurred
#0      breedMoreLlamas (file:///D:/dartdemo/firstdart/bin/firstdart.dart:2:27)
#1      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:5)
#2      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#3      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

2: try + catch + finally

Standard template for resource release, e.g. closing file streams

void cleanLlamaStalls() => print("Close files / release occupied resources");
void breedMoreLlamas() => throw FormatException("Parsing failed");

void main() {
  try {
    breedMoreLlamas();
  } catch (e) {
    print("Caught exception: $e");
  } finally {
    cleanLlamaStalls();
  }
}
Code language: Dart (dart)

Execution order: Error triggered → catch block runs → finally block executes last

Execution output

D:\dartdemo\firstdart>dart run
Building package executable...
Built firstdart:firstdart.
Caught exception: FormatException: Parsing failed
Close files / release occupied resources
Code language: PHP (php)

assert Assertions

Only active during development & debugging; fully disabled in production builds

assert(booleanCondition, [optionalErrorText])

Throws AssertionError when condition evaluates to false; completely ignored in release builds with zero performance overhead.

1: Basic assertion example

void main() {
  String? text;
  int number = 120;
  String url = "http://foxdevelop.com";

  assert(text != null); // Nullability check
  assert(number < 100); // Numeric range validation
  assert(url.startsWith("https")); // URL protocol check
}
Code language: JavaScript (javascript)

Running this code produces no visible output by default!

Assertions are turned off globally unless you explicitly enable them via launch flags, read below for details.

2: Custom human-readable error message

void main() {
  String url = "http://test.com";
  assert(
    url.startsWith("https"),
    "URL $url must start with https protocol",
  );
}
Code language: JavaScript (javascript)

We can define custom descriptive text to show when an assertion fails.

How to Enable Assertions

  1. Flutter Debug mode enables assertions by default
  2. Direct dart command: dart --enable-asserts your-file-name.dart
  3. Production compilation: All assertions are stripped entirely with no runtime cost
D:\dartdemo\firstdart\bin>dart --enable-asserts firstdart.dart
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

dart run behaves the same as raw dart command; assertions stay disabled unless you add the --enable-asserts flag:

Run command example:

dart run --enable-asserts main.dartCode language: CSS (css)

If your terminal working directory is the project root, run this shorthand:

Run command:

dart run --enable-asserts

dart run: Directly execute Dart source files for local development testing

dart filename: Simplified single-file run syntax

dart compile exe: Build standalone binary executables; assertions are permanently disabled in compiled output

The Dart source file lives inside the bin subfolder, so you can either cd into bin to run the file directly, or execute the command from the project root folder one level above bin.

dart run –enable-asserts

Below shows both execution methods: running inside bin folder, and running from project root parent directory.

D:\dartdemo\firstdart\bin>dart --enable-asserts firstdart.dart
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)

D:\dartdemo\firstdart\bin>dart run
Building package executable...
Built firstdart:firstdart.

D:\dartdemo\firstdart\bin>cd ..

D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.
Unhandled exception:
'file:///D:/dartdemo/firstdart/bin/firstdart.dart': Failed assertion: line 6 pos 10: 'text != null': is not true.
#0      _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:67:4)
#1      _AssertionError._throwNew (dart:core-patch/errors_patch.dart:49:5)
#2      main (file:///D:/dartdemo/firstdart/bin/firstdart.dart:6:10)
#3      _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:314:19)
#4      _RawReceivePort._handleMessage (dart:isolate-patch/isolate_patch.dart:193:12)Code language: PHP (php)

No error will be thrown if the assertion condition evaluates to true

Modify the example code: change http to https on url, switch text != null to text == null, set number value to 99

void main() {
  String? text;
  int number = 99;
  String url = "https://foxdevelop.com";

  assert(text == null); // Nullability check
  assert(number < 100); // Numeric range validation
  assert(url.startsWith("https")); // URL protocol check
}Code language: Dart (dart)

Running this updated version outputs zero errors

D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.Code language: CSS (css)

Full Combined Demo

void cleanResource() => print("finally block: Release occupied resources");

void testError() {
  try {
    int num = 150;
    assert(num < 100, "Number value must be less than 100");
    throw FormatException("Invalid data format");
  } on FormatException catch (e) {
    print("Caught format exception: $e");
    rethrow;
  } finally {
    cleanResource();
  }
}

void main() {
  try {
    testError();
  } catch (e) {
    print("main catches re-thrown exception: $e");
  }
}
Code language: PHP (php)

Execution output

D:\dartdemo\firstdart>dart run --enable-asserts
Building package executable...
Built firstdart:firstdart.
finally block: Release occupied resources
main catches re-thrown exception: 'file:///D:/dartdemo/firstdart/bin/firstdart.dart':
 Failed assertion: line 6 pos 12: 'num < 100': Number value must be less than 100Code language: PHP (php)

Leave a Reply

Your email address will not be published. Required fields are marked *