Skip to content

ErrorWidget.builder not working on profile/release #109382

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
zmtzawqlp opened this issue Aug 11, 2022 · 7 comments
Closed

ErrorWidget.builder not working on profile/release #109382

zmtzawqlp opened this issue Aug 11, 2022 · 7 comments
Labels
a: error message Error messages from the Flutter framework a: release Challenges faced when attempting to productionize an app found in release: 3.0 Found to occur in 3.0 found in release: 3.1 Found to occur in 3.1 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on

Comments

@zmtzawqlp
Copy link
Contributor

zmtzawqlp commented Aug 11, 2022

Steps to Reproduce

  1. Execute flutter run --profile on the code sample

Expected results: show Custom error widget

Actual results: white screen

Code sample
import 'package:flutter/material.dart';

Widget _defaultErrorWidgetBuilder(FlutterErrorDetails details) {
  String message = '';

  message =
      '${details.exception}\nSee also: https://flutter.dev/docs/testing/errors';

  final Object exception = details.exception;
  return ErrorWidget.withDetails(
      message: message, error: exception is FlutterError ? exception : null);
}

void main() {
  ErrorWidget.builder = (FlutterErrorDetails details) {
    return Material(
      child: Container(
        color: Colors.purple,
        alignment: Alignment.center,
        child: const Text(
          'Something went wrong!',
          style: TextStyle(fontSize: 20, color: Colors.white),
        ),
      ),
    );
  };
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Column(children: <Widget>[
        Positioned(
            child: Container(
          height: 10,
          width: 10,
          color: Colors.red,
        ))
      ]),

      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}
[✓] Flutter (Channel stable, 3.0.5, on macOS 12.4 21F79 darwin-x64, locale zh-Hans-CN)
    • Flutter version 3.0.5 at /Users/zmtzawqlp/Documents/flutter/3.0.0
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision f1875d570e (4 weeks ago), 2022-07-13 11:24:16 -0700
    • Engine revision e85ea0e79c
    • Dart version 2.17.6
    • DevTools version 2.12.2
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /Users/zmtzawqlp/Library/Android/sdk
    • Platform android-32, build-tools 30.0.3
    • ANDROID_HOME = /Users/zmtzawqlp/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.69.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.46.0

[✓] Connected device (3 available)
    • MI 9 (mobile)   • f65dae09 • android-arm64  • Android 11 (API 30)
    • macOS (desktop) • macos    • darwin-x64     • macOS 12.4 21F79 darwin-x64
    • Chrome (web)    • chrome   • web-javascript • Google Chrome 104.0.5112.79

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
@zmtzawqlp zmtzawqlp changed the title ErrorWidget.builder not working ErrorWidget.builder not working on profile/release Aug 11, 2022
@maheshj01 maheshj01 added the in triage Presently being triaged by the triage team label Aug 11, 2022
@maheshj01
Copy link
Member

maheshj01 commented Aug 11, 2022

Hi @zmtzawqlp, Thanks for filing the issue. I am able to reproduce the issue. Looks like the error is not being reporte. When the exception occurs in release mode ErrorWidget.builder isn't being called. But if you manually throw the error in build then the ErorrWidget is shown.

code sample (works)
import 'package:flutter/material.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  ErrorWidget.builder = (FlutterErrorDetails details) {
    return Material(
      child: Container(
        color: Colors.purple,
        alignment: Alignment.center,
        child: const Text(
          'Something went wrong!',
          style: TextStyle(fontSize: 20, color: Colors.white),
        ),
      ),
    );
  };
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    throw 'Something went wrong!';
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: <Widget>[
        Positioned(
            child: Container(
          height: 10,
          width: 10,
          color: Colors.red,
        ))
      ]),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
code sample (doesn't work)
import 'package:flutter/material.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  ErrorWidget.builder = (FlutterErrorDetails details) {
    return Material(
      child: Container(
        color: Colors.purple,
        alignment: Alignment.center,
        child: const Text(
          'Something went wrong!',
          style: TextStyle(fontSize: 20, color: Colors.white),
        ),
      ),
    );
  };
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(children: <Widget>[
        Positioned(
            child: Container(
          height: 10,
          width: 10,
          color: Colors.red,
        ))
      ]),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}
flutter doctor -v (mac)
[✓] Flutter (Channel stable, 3.0.5, on macOS 12.4 21F79 darwin-arm, locale en-IN)
    • Flutter version 3.0.5 at /Users/mahesh/Documents/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision f1875d570e (5 days ago), 2022-07-13 11:24:16 -0700
    • Engine revision e85ea0e79c
    • Dart version 2.17.6
    • DevTools version 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-32, build-tools 33.0.0-rc4
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 61.2.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.67.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.44.0

[✓] Connected device (3 available)
    • sdk gphone arm64 (mobile) • emulator-5554 • android-arm64  • Android 11 (API 30) (emulator)
    • macOS (desktop)           • macos         • darwin-arm64   • macOS 12.4 21F79 darwin-arm
    • Chrome (web)              • chrome        • web-javascript • Google Chrome 103.0.5060.114

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!
[✓] Flutter (Channel master, 3.1.0-0.0.pre.2186, on macOS 12.4 21F79 darwin-arm, locale en-IN)
    • Flutter version 3.1.0-0.0.pre.2186 on channel master at /Users/mahesh/Documents/flutter_master
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 458c7b9c65 (31 hours ago), 2022-08-10 03:19:07 -0400
    • Engine revision 75e17f1a6f
    • Dart version 2.19.0 (build 2.19.0-81.0.dev)
    • DevTools version 2.16.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0-rc4)
    • Android SDK at /Users/mahesh/Library/Android/sdk
    • Platform android-32, build-tools 33.0.0-rc4
    • ANDROID_HOME = /Users/mahesh/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 13C100
    • CocoaPods version 1.11.2

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] IntelliJ IDEA Community Edition (version 2021.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 61.2.4
    • Dart plugin version 212.5080.8

[✓] VS Code (version 1.69.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.46.0

[✓] Connected device (3 available)
    • sdk gphone arm64 (mobile) • emulator-5554 • android-arm64  • Android 11 (API 30) (emulator)
    • macOS (desktop)           • macos         • darwin-arm64   • macOS 12.4 21F79 darwin-arm
    • Chrome (web)              • chrome        • web-javascript • Google Chrome 104.0.5112.79

[✓] HTTP Host Availability
    • All required HTTP hosts are available

• No issues found!

@maheshj01 maheshj01 added framework flutter/packages/flutter repository. See also f: labels. a: error message Error messages from the Flutter framework has reproducible steps The issue has been confirmed reproducible and is ready to work on found in release: 3.0 Found to occur in 3.0 found in release: 3.1 Found to occur in 3.1 a: release Challenges faced when attempting to productionize an app and removed in triage Presently being triaged by the triage team labels Aug 11, 2022
@zmtzawqlp
Copy link
Contributor Author

zmtzawqlp commented Aug 12, 2022

@maheshmnj if you replace ErrorWidget.builder = _defaultErrorWidgetBuilder; error info will be shown in release

@goderbauer
Copy link
Member

I have verified that ErrorWidget.builder works in profile and release mode with the snippet below. It's possible that the error widget you're trying to build is actually itself throwing an error and that's causing you to see the white screen. When writing an ErrorWidget you have to take great care that it cannot fail to build as there is no back up.

import "package:flutter/material.dart";

void main() {
  ErrorWidget.builder = (FlutterErrorDetails details) {
    return Container(color: Colors.green);
  };

  runApp(const MaterialApp(home: Scaffold(body: MyApp())));
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    throw "help!";
  }
}

@zmtzawqlp
Copy link
Contributor Author

zmtzawqlp commented Aug 17, 2022

it should has a way to show such error in release. demo in debug, just show error in console, it's easy miss those infos if your app has many debug info.

@maheshj01
Copy link
Member

@goderbauer wondering if we have to manually throw errors for ErrorWidget.builder to catch, Then How are we supposed to handle errors caused by the code sample in the original report incorrect use of parent widget or such errors are not caught by ErrorWidget.builder?

@zmtzawqlp
Copy link
Contributor Author

zmtzawqlp commented Aug 19, 2022

I notice: the description of ErrorWidget.builder

/// When an error occurs while building a widget, the broken widget is
/// replaced by the widget returned by this function. By default, an
/// [ErrorWidget] is returned.

That why demo code does not work, the replaced widget also has error, so it's drop-dead halt.

i think ErrorWidget.builder should not be public to the user. Not all users are professional. The following codes may be more safety.

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';

void main() {
  // ErrorWidget.builder = (FlutterErrorDetails details) {
  //   return Material(
  //     child: Container(
  //       color: Colors.purple,
  //       alignment: Alignment.center,
  //       child: const Text(
  //         'Something went wrong!',
  //         style: TextStyle(fontSize: 20, color: Colors.white),
  //       ),
  //     ),
  //   );
  // };

  FlutterError.onError = _onError;

  runZonedGuarded<void>(() async {
    runApp(const MyApp());
  },
      ((error, stack) => _onError(FlutterErrorDetails(
            exception: error,
            stack: stack,
          ))));
}

void _onError(FlutterErrorDetails details) {
  WidgetsBinding.instance.addPostFrameCallback(
    (timeStamp) {
      showDialog(
        context: MyApp.navigatorKey.currentContext!,
        builder: (b) {
          return Padding(
            padding: const EdgeInsets.all(20.0),
            child: GestureDetector(
              onTap: () {
                Navigator.of(b).pop();
              },
              child: Material(
                child: Container(
                  padding: EdgeInsets.all(10),
                  child: SingleChildScrollView(
                      child: Column(
                    children: <Widget>[
                      Text('exception:'),
                      Text('${details.exception}'),
                      Text('stack:'),
                      Text('${details.stack}'),
                    ],
                  )),
                ),
              ),
            ),
          );
        },
      );
    },
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      navigatorKey: navigatorKey,
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Stack(children: <Widget>[
        GestureDetector(
          child: Positioned(
            child: Container(
              height: 10,
              width: 10,
              color: Colors.red,
            ),
          ),
        )
      ]),

      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

@github-actions
Copy link

github-actions bot commented Sep 2, 2022

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.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 2, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
a: error message Error messages from the Flutter framework a: release Challenges faced when attempting to productionize an app found in release: 3.0 Found to occur in 3.0 found in release: 3.1 Found to occur in 3.1 framework flutter/packages/flutter repository. See also f: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on
Projects
None yet
Development

No branches or pull requests

3 participants