Skip to content
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

exceptions thrown by Flutter apps end up displayed on the console via dartPrint instead of window.oneerror #3148

Open
csells opened this issue Feb 15, 2025 · 7 comments
Assignees
Labels
area-error-messaging type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)

Comments

@csells
Copy link
Collaborator

csells commented Feb 15, 2025

What happened?

I'm trying to add a feature to the console that only shows itself when there's an error in the console and not just someone calling print. I'm using the _consoleShowingError field of the AppModel, which is set when there's an exception message posted from the iframe hosting the app. Unfortunately, as far as I can tell, the _consoleShowingError flag is never set, because the JS window.onerror handler defined in frame.dart is never called. Instead, where there's an error in the app being hosted in DartPad, it's routed FlutterError.reportError for Flutter apps and to something else (haven't figured out what) for Dart apps. This handler in turn routes the exception message through the dartPrint method (also defined in frame.dart) in the same way that a call to print works. The exception ends up in the console but there's no way to tell that message from a call to print.

Steps to reproduce problem

  1. add a throw 'oops' call to your program, making sure not to wrap it in a try-catch block.
  2. run the program
  3. the message posted by the iframe will show up in the _initListener function in frame.dart with data['type'] set to 'stdout' (set by the dartPrint function) instead of 'stderr' (set by the window.onerror) handler.

There still needs to be some work to set _consoleShowingError to true when a message with data['type'] set to stderr is handled, but that work can't happen with exceptions and print calls both routing to dartPrint.

Additional info

Browser

Browser: Chrome

Version: 133.0.6943.55 (Official Build) (arm64)

Are you using any extensions/plugins that affect website behavior
(particularly those that affect iframes, such as ad blockers)?
None I can think of.

Are there any warnings or errors in your browser's JavaScript console?
If so, paste them below:
None that seem to have any bearing.

Machine

Operating system: macOS

Version: 15.3 (24D60)

Your code

What code was in the editor, if any, when the failure occurred? You
can paste it in below:

void main() {
  throw 'oops';
}

DartPad's output

Did DartPad print anything to the console pane? If so, paste it below:

DartPad caught unhandled String:
oops
https://storage.googleapis.com/nnbd_artifacts/3.8.0-91.0.dev/dart_sdk_new.js 3732:11       Object.throw_
Stack trace truncated and adjusted by DartPad...

If you were running Flutter code, you can also paste an image of the
Flutter output directly into this bug report.
n/a

@csells csells added the type-bug Incorrect behavior (everything from a crash to more subtle misbehavior) label Feb 15, 2025
csells added a commit to csells/dart-pad that referenced this issue Feb 15, 2025
… in the console based on the error state of the app
@johnpryan
Copy link
Contributor

DartPad's error handling has been problematic because the framework intercepts all errors and reports them to the JS console as normal console output. I'm able to make frame.dart receive a stderr type in a Flutter app using the following source code:

import 'package:flutter/material.dart';

void main() {
  FlutterError.onError = (details) {
    throw(details);
    // FlutterError.presentError(details);
  };
  runApp(const MainApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: TextButton(
            onPressed: () {
              throw ('oops');
            },
            child: Text('foo'),
          ),
        ),
      ),
    );
  }
}

I think the best way to solve this would be to configure the Flutter engine to report errors differently. @ditman do you know if there's a way to configure how errors are reported on the web?

@johnpryan
Copy link
Contributor

As @parlough pointed out, we already wrap the user's main so it should be easy to add this code to all DartPad scripts

@csells
Copy link
Collaborator Author

csells commented Feb 27, 2025

would that work for Dart, too, or just Flutter?

@johnpryan
Copy link
Contributor

Dart scripts currently report errors correctly, no?

@csells
Copy link
Collaborator Author

csells commented Feb 27, 2025

no

@johnpryan
Copy link
Contributor

I was able to make frame.dart receive a stderr type in a Flutter app using a normal Dart script, could you share more details?

@johnpryan johnpryan self-assigned this Feb 27, 2025
@csells
Copy link
Collaborator Author

csells commented Feb 28, 2025

you're right, @johnpryan. my initial testing showed that unhandled exceptions from both Dart and Flutter resulted in a message not routed to stderr but now that's only true for Flutter; unhandled Dart exceptions do end up in stderr output.

And it's pretty great that only a single LOC in the Flutter main fixes the Flutter problem, too:

void main() {
  FlutterError.onError = (err) => throw err;
  run(...);
}
...

if we could inject this single LOC, we'd be able to properly detect a console that contains text associated with errors and then properly enable the Suggest Fix feature.

I know you're working on this issue; once it's handled, I'll fix the Suggest Fix problem.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-error-messaging type-bug Incorrect behavior (everything from a crash to more subtle misbehavior)
Projects
None yet
Development

No branches or pull requests

2 participants