Skip to content

ExceptionHandler Widget #19993

Closed
Closed

Description

@escamoteur

@eseidelGoogle As discussed here is the issue:

Currently we don't have a possibility to handle Exceptions that happens inside a Widget somewhere down the widget tree. I would propose a Widget that allows that. Something like

typedef ExceptionHandler = void Function( ex)
typedef AlternativeBuilder = void Function(BuildingContext context, ex)


ExceptionHandledBuilder(
   List<Object>  exceptionsToCatch,           // Exceptions that should behandled  (It's really a pity that Dart doesen't have a common Exception base class)
   HandlerFunction: onException,               // get's called to allow logging or what else
   AlternativeBuilder: alternativeBuilder,     // Builder that get's invoked while executing the normal builder method
   AsyncWidgetBuilder<T>: builder);          // the default builder that tryies to bild the child widget tree.

I'm not sure if something like this is possible.

What are your thoughts?

Activity

  1. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Jul 30, 2018
  2. added this to the milestone on Jul 30, 2018
  3. eseidelGoogle commented on Jul 30, 2018

    @eseidelGoogle
    Contributor

    @Hixie and @leafpetersen are the right folks for thoughts probably.

  4. leafpetersen commented on Jul 30, 2018

    @leafpetersen
    Contributor

    I don't have a lot of thoughts from the language perspective (as opposed to the API perspective), other than to wonder whether support for implicitly lazy parameters would clean this up a bit? cc @munificent

  5. Hixie commented on Jul 30, 2018

    @Hixie
    Contributor

    @escamoteur What's the use case here?

  6. zoechi commented on Jul 31, 2018

    @zoechi
    Contributor

    I guess the first bullet of #19996

  7. escamoteur commented on Jul 31, 2018

    @escamoteur
    ContributorAuthor

    @Hixie if I call a function to assign a value inside the widget tree that could throw an exception I have no chance to handle this. Sure I could do such calls at the beginning of the build method with a try-catch and set some bool flags to display different contents but I think there should be a better way to achieve that

  8. munificent commented on Aug 2, 2018

    @munificent
    Contributor

    Ah, so the issue is that in the middle of building a tree of widgets, an exception might occur. You want to be able to catch it and provide an alternate subtree instead of the failed one?

    Something like:

    Widget hopefullyMakeText() {
      if (sometimes) throw "Oh no!";
    
      return Text('Hello, world!');
    }
    
    Widget build() {
      return Center(child: hopefullyMakeText());
    }

    And you want to be able to handle that exception and swap out the widget without having to do:

    Widget build() {
      // Hoist everything out of expression.
      Widget child;
      try {
        child = hopefullyMakeText();
      } catch (error) {
        child = Text('Fallback');
      }
    
      return Center(child: child);
    }

    Do I have that right? You can always solve this at the application level by writing a utility function:

    Widget definitelyMakeText() {
      try {
        return hopefullyMakeText();
      } catch (error) {
        return Text('Fallback');
      }
    }
    
    Widget build() {
      return Center(child: definitelyMakeText());
    }

    If Dart were an expression-oriented language, I could imagine that it would allow something like:

    Widget build() {
      return Center(
        child: try {
          hopefullyMakeText();
        } catch (error) {
          Text('Fallback');
        }
      );
    }

    I'm definitely not proposing that, but that is a way it could be solved in the language.

    As far as your original question, yes, it's possible. Here's one way:

    T handleException<T>(T Function() original, T Function() fallback) {
      try {
        return original();
      } catch (error) {
        return fallback();
      }
    }

    Then you'd use it like:

    Widget build() {
      return Center(
        child: handleException(hopefullyMakeText, () => Text('Fallback'))
      );
    }

    It would be easy to extend handleException() to let you control which exceptions it catches.

  9. added
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 3, 2018
  10. zoechi commented on Sep 3, 2018

    @zoechi
    Contributor

    @escamoteur what do you think about @munificent's suggestion?

  11. escamoteur commented on Sep 5, 2018

    @escamoteur
    ContributorAuthor

    Yeah, that is a completely feasible solution. My suggestion from the beginning was if something like that shouldn't be part of the framework. @eseidelGoogle

  12. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 5, 2018
  13. Hixie commented on Sep 12, 2018

    @Hixie
    Contributor

    I would recommend making your build methods not ever throw. Don't read data from a database within your build methods, for example; read the data in your model objects, asynchronously, and have the build methods read from your model in a way guaranteed not to throw.

    But if that's not a thing you want to do, consider making a variant of Builder that catches exceptions, something like (untested):

    class SafeBuilder extends StatelessWidget {
      SafeBuilder({
        Key key,
        this.builder,
      }) : super(key: key);
      final WidgetBuilder builder;
      @override
      Widget build(BuildContext context) {
        try {
          return builder(context);
        } catch (error) {
          return ErrorWidget(error);
        }
      }
    }

    If you want custom handling for the error, you can call a different builder instead of ErrorWidget.

    Also you may wish to look at ErrorWidget.builder, which is a more global way to catch errors.

  14. escamoteur commented on Sep 18, 2018

    @escamoteur
    ContributorAuthor

    @Hixie that looks like an interesting idea. I agree with you that normally this should not happen. Anyway I still think such a widget should be part of the framework in case you need it e.g. if a Widget from a package throws exception under certain conditions.

  15. Hixie commented on Oct 6, 2018

    @Hixie
    Contributor

    We don't really want to encourage people to consider it to be ok to throw in a builder. We technically already wrap most builders in a try/catch, that's how ErrorWidget.builder gets called.

  16. modified the milestones: , on Jan 3, 2019
  17. goderbauer commented on Jan 3, 2019

    @goderbauer
    Member

    Closing based on the comment above from @Hixie.

  18. rrousselGit commented on Jul 2, 2019

    @rrousselGit
    Contributor

    #19993 (comment)

    This is not a solution. Error boundaries are not just about build methods.

    They are for any kind of exceptions that comes from the descendants. This also includes:

    • click handlers
    • uncaught futures in FutureBuilder
    • other widgets lifecycles

    The exception can also happens from a widget very deep down in the widget tree.
    The catcher is not necesseraly the widget that threw.

  19. eseidelGoogle commented on Jul 9, 2019

    @eseidelGoogle
    Contributor

    @rrousselGit I think to revive this discussion we're going to need to engage in something a bit more long-form. Can you provide examples of what you're trying to achieve? (e.g. I want to have a click-handler which might throw and when it does I want to do X.)

    There is discussion of error reporting in https://flutter.dev/docs/cookbook/maintenance/error-reporting. As Ian notes, there is already an ErrorWidget. But it's not clear from your comment what your asking for.

    In any case, this bug is long and it might be time to start a new one, clearly stating the problem and desired outcome and let folks hash out what the right solutions then should be?

  20. escamoteur commented on Mar 12, 2020

    @escamoteur
    ContributorAuthor

    I'm currently faced with the situation that it can happen that a file a FileImage tries to load does not exists. Currently there is only a loadingBuilder but not an ErrorBuilder. This just as an example.

  21. escamoteur commented on Mar 12, 2020

    @escamoteur
    ContributorAuthor

    The handleException og @munificent solved it for now. I still think we should have something like this in the framework

  22. escamoteur commented on Mar 12, 2020

    @escamoteur
    ContributorAuthor

    I have to correct me. The exception that is thrown by the imagestream never reaches the Widgettree. it is swallowed somewhere.

  23. lock commented on Apr 4, 2020

    @lock

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  24. locked and limited conversation to collaborators on Apr 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: new featureNothing broken; request for a new capabilityframeworkflutter/packages/flutter repository. See also f: labels.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions