stack_trace icon indicating copy to clipboard operation
stack_trace copied to clipboard

Cannot use `catch` anymore when using `Chain.capture`

Open fzyzcjy opened this issue 4 years ago • 2 comments

Very simple example:

void main() async {
  try {
    await g();
  } catch (e) {
    print('catch e=$e');
  }
}

Future<void> g() {
  throw Exception('fake error');
}

As expected, the output is catch e=Exception: fake error.

However, by wrapping g with Chain.capture as follows:

Future<void> g() {
  return Chain.capture(() async {
    throw Exception('fake error');
  });
}

Our catch no longer works! See below:

[VERBOSE-2:ui_dart_state.cc(199)] Unhandled Exception: Exception: fake error
package:yplusplus/main.dart 60:5              g.<fn>
package:yplusplus/main.dart 59:24             g.<fn>
package:stack_trace/src/chain.dart 94:24      Chain.capture.<fn>
dart:async/zone.dart 1354:13                  _rootRun
dart:async/zone.dart 1258:19                  _CustomZone.run
dart:async/zone.dart 1789:10                  _runZoned
dart:async/zone.dart 1711:10                  runZoned
package:stack_trace/src/chain.dart 92:12      Chain.capture
package:yplusplus/main.dart 59:16             g
package:yplusplus/main.dart 52:11             main
dart:ui/hooks.dart 142:25                     _runMainZoned.<fn>.<fn>
dart:async/zone.dart 1354:13                  _rootRun
dart:async/zone.dart 1258:19                  _CustomZone.run
dart:async/zone.dart 1789:10                  _runZoned
dart:async/zone.dart 1777:12                  runZonedGuarded
dart:ui/hooks.dart 138:5                      _runMainZoned.<fn>
dart:isola<…>

This is very counter-intuitive. I wonder how can I solve this problem? In other words, I want to have the full stack trace (so I use capture), but at the same time, I want catch to work!

Thanks for any suggestions!

fzyzcjy avatar Jul 25 '21 09:07 fzyzcjy

Chain.capture creates a new error zone and runs the given function in it, if invoked with the default arguments. Errors cannot cross error zones, so awaiting the result of Chain.capture cannot catch errors and any errors are unhandled exceptions in the error zone created by Chain.capture.

You can disable the creation of a new error zone with Chain.capture(..., errorZone: false).

blaugold avatar Jan 26 '22 14:01 blaugold

@blaugold Your solution with errorZone: false will make it "catchable" again but we lose the "stack chains" feature advertised by this library.

Is there any way to have the full async stack trace while also catchable?

Edit:

I found a solution:

Never rethrowWithNewStackTrace(Object error, StackTrace stackTrace) {
  Error.throwWithStackTrace(
    error,
    StackTrace.fromString(
      '$stackTrace===== asynchronous gap ===========================\n${StackTrace.current}',
    ),
  );
}

Tienisto avatar Sep 03 '23 00:09 Tienisto