16

Let's say in a Flutter app we want to catch any uncaught exceptions/errors at the top level, so we do this as per the docs:

main() { // All uncaught errors thrown from synchronous code blocks will end up here: FlutterError.onError = (FlutterErrorDetails details) { MyLogger.instance.logUncaughtErrorSync(details); }; // All uncaught errors thrown from async code blocks will end up here: PlatformDispatcher.instance.onError = (Object error, StackTrace stack) { MyLogger.instance.logUncaughtErrorASync(error, stack); return true; }; runApp(const MyApp()); 

While the docs seems to imply that the distinction between the two is whether the error originated in Dart (and specifically "Flutter") code vs platform (Android/IOS) code, through my testing, the only difference I can tell between the two is whether the Object (error) was thrown from async vs sync Dart code.

For example, if in Dart code, (not platform code), we simply put:

_function() async { throw('error'); } 

and we call that function, it will bubble up through the "platform dispatcher" and is considered a "platform error," but seemingly only because it happened on a background thread?

There appears to actually be no mechanism allowing Exceptions thrown from Java or Swift code to trigger either of these onError functions.

There must be more to it than this though, so whats the point of having two separate mechanisms (with different inputs -- FlutterErrorDetails vs Object+StackTrace)... and what's the real difference?

2 Answers 2

8

In fact, the answer is provided in the documentation page you referenced.

FlutterError.onError is meant for Flutter framework errors - errors that happen at the framework level (errors encountered during the build, layout, and paint phases). In simple words, if you have an error that happens because of your written Dart code or the one in the Flutter framework, it goes to FlutterError.onError.

On the other hand, PlatformDispatcher.instance.onError is meant for platform-level errors. As you may know, Flutter supports multiple platforms and those execute the code in their native layer. For instance, you use plugins or you implement your own Flutter plugin code using Platform channels:

OutlinedButton( child: const Text('Click me!'), onPressed: () async { const channel = MethodChannel('crashy-custom-channel') await channel.invokeMethod('blah') }, ) 

In such case, this is not a Flutter-level error anymore, thus it will be forwarded to PlatformDispatcher.instance.onError.

Sign up to request clarification or add additional context in comments.

3 Comments

Yes that was my initial understanding also, because of the naming they use and the examples they give, however after testing it it seems it has nothing whatsoever to do with the nature of the error and only whether not the error happed in sync dart code vs async dart code. For example in that button , you could have onPressed: () async {throw “poo”;} and it would still be a “platform error”
In my case i throw Exception from onError of Bloc and I see it in PlatformDispatcher.instance.onError
This is not answering the question asked.
0

I think you were already extremely close to the answer. Like you said the async stuff, or more importantly things that are running outside the main lifecycle can only be caught through the PlatformDispatcher. You can think of that as an error handler thats outside the onError callback. So if onError doesn't catch the error it reaches this handler. And async code doesn't get to onError

There appears to actually be no mechanism allowing Exceptions thrown from Java or Swift code to trigger either of these onError functions.

This is supposed to be handled through callbacks. Here's the signature for a typical ios native platform method implementation

(void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result 

which expects a FlutterResult. But what's of interest here to this question is that it can also be a FlutterError for example inside the native code's try catch or error handling you can call

result([FlutterError errorWithCode:@"ERROR_ALREADY_REQUESTING_PERMISSIONS" message:@"A request for permissions is already running, please wait for it to finish before doing another request (note that you can request multiple permissions at the same time)." details:nil]); 

So now the error has come into the dart/flutter realm. But being a platform method it's async so will show up in the PlatformDispatcher error handling.

FlutterErrorDetails vs Object+StackTrace

I think this should now be self-explanatory. FlutterErrorDetails is a stricter type that contains stack trace and exception object inside it among other fields. These other fields are non-standard for error handling so object + stacktrace is used for the more general error handler that can be coming from any platform

This is based on my experience and if anyone sees different behaviour than I have described here, I would love to know

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.