Dart Stream Errors
A stream error is an event that reports a failure instead of carrying a value. Listener callbacks and stream tools can catch these errors and decide whether the stream continues.
An error that stops the subscription
The generator yields 1 and 2, then throws. The onError callback prints the error, and cancelOnError set to true ends the subscription at that point.
import 'dart:async';
Stream<int> risky() async* {
yield 1;
yield 2;
throw StateError('too far');
}
void main() {
risky().listen(
(value) {
print(value);
},
onError: (error) {
print('error: $error');
print('stopped');
},
cancelOnError: true,
);
}Good values continue past an error
The map step throws for the value 0, and handleError receives that error and drops it. The values before and after the bad one still print, and the stream finishes normally.
import 'dart:async';
void main() {
var values = Stream.fromIterable([1, 2, 0, 3]).map((number) {
if (number == 0) {
throw StateError('bad value');
}
return number;
}).handleError((error) {});
values.listen(
(value) {
print('got $value');
},
onDone: () {
print('finished');
},
);
}Catching an error around await for
The generator yields 5 and 6, then throws a StateError. The catch block prints the message inside the error, and the line after the block still runs.
import 'dart:async';
Stream<int> risky() async* {
yield 5;
yield 6;
throw StateError('limit reached');
}
Future<void> main() async {
try {
await for (var value in risky()) {
print(value);
}
} on StateError catch (error) {
print(error.message);
}
print('after');
}Example
import 'dart:async';
Stream<int> readings() async* {
yield 4;
yield 8;
throw StateError('sensor failed');
}
void main() {
var count = 0;
readings().listen(
(value) {
count++;
print('reading $value');
},
onError: (error) {
print('logged $error');
},
onDone: () {
print('processed $count readings');
},
);
}Key points
- A stream delivers an error as an event when something fails while values are being produced.
- The onError callback of listen receives the error so the program can react to it.
- cancelOnError set to true ends the subscription as soon as an error arrives.
- handleError catches an error in the middle of a stream and lets the values after it continue.
- A try and catch block around await for catches an error thrown by a generator in the same way as ordinary code.
In this example, the listener counts and prints each reading that arrives safely. The generator then throws, and the onError callback logs the error instead of letting it end the program. The stream closes after the error, so the done handler prints the summary of 2 readings.
Note
An error that nobody catches ends the program, so a stream that can fail needs a handler.
Try it Yourself
Edit the code, then press Run.
Running is simulated · DartPad
Exercise
What does cancelOnError set to true do in a listen call?