I'm having trouble working out how I can catch exceptions from isolates. With the following code, I've tried everything I can think of to handle the error that is thrown from task
, but it's still marked as Unhandled exception
.
void main() async {
try {
var rp = ReceivePort();
rp.listen((message) {
print(message);
}, onError: (e) {
print(e);
});
rp.handleError((e) {
print(e);
});
var isolate = await Isolate.spawn(task, rp.sendPort);
isolate.addErrorListener(rp.sendPort);
} catch (e) {
print(e);
}
}
void task(SendPort sp) {
sp.send('hello from isolate');
throw Exception();
}
What am I missing here?
EDIT: From the below answer, my solution should look like this:
void main() async {
var rp = ReceivePort();
var errorRp = ReceivePort();
errorRp.listen((e) {
print('exception occured');
print(e);
});
rp.listen(print);
await Isolate.spawn(task, rp.sendPort, onError: errorRp.sendPort);
await Future.delayed(Duration(seconds: 1));
rp.close();
errorRp.close();
}
void task(SendPort sp) {
sp.send('hello from isolate');
throw Exception();
}
I think you have missed an important segment of the documentation for Isolate.spawn
:
You can also call the
setErrorsFatal
,addOnExitListener
andaddErrorListener
methods on the returned isolate, but unless the isolate was started aspaused
, it may already have terminated before those methods can complete.
You issue is that your spawned Isolate
has already executed throw Exception()
before your isolate.addErrorListener(rp.sendPort);
has been executed.
Instead, do something like this to spawn the Isolate
as paused
and then later resume
it:
var isolate = await Isolate.spawn(task, rp.sendPort, paused: true);
isolate.addErrorListener(rp.sendPort);
isolate.resume(isolate.pauseCapability!);
Alternative, you can just give the Isolate
your error handler as part of spawning:
var isolate = await Isolate.spawn(task, rp.sendPort, onError: rp.sendPort);