{"id":32290963,"url":"https://github.com/ppicas/error_trace","last_synced_at":"2026-05-14T20:02:14.429Z","repository":{"id":275130016,"uuid":"735104748","full_name":"ppicas/error_trace","owner":"ppicas","description":"Dart utilities to preserve stack traces across asynchronous calls for better debugging","archived":false,"fork":false,"pushed_at":"2025-01-31T18:16:52.000Z","size":44,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-23T02:59:53.765Z","etag":null,"topics":["dart","debugging","error-handling","flutter","stacktrace"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/error_trace","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ppicas.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-12-23T17:19:18.000Z","updated_at":"2025-06-17T09:15:05.000Z","dependencies_parsed_at":"2025-01-31T11:50:39.367Z","dependency_job_id":"6a53493f-2244-4a9b-99ce-8b62c2786acb","html_url":"https://github.com/ppicas/error_trace","commit_stats":null,"previous_names":["ppicas/error_trace"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ppicas/error_trace","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppicas%2Ferror_trace","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppicas%2Ferror_trace/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppicas%2Ferror_trace/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppicas%2Ferror_trace/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ppicas","download_url":"https://codeload.github.com/ppicas/error_trace/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ppicas%2Ferror_trace/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33041204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","debugging","error-handling","flutter","stacktrace"],"created_at":"2025-10-23T02:59:44.778Z","updated_at":"2026-05-14T20:02:14.395Z","avatar_url":"https://github.com/ppicas.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"Dart utilities to preserve stack traces across asynchronous calls for better debugging.\n\nWith `error_trace` you can get full stack traces that include the whole chain of calls, even if\nthere are asynchronous gaps in the middle. This makes it easier to debug Dart and Flutter\napplications.\n\n\u003cdetails\u003e\n\u003csummary\u003eBackground: Problems with exceptions in asynchronous calls\u003c/summary\u003e\n\nDebugging errors in asynchronous Dart code can be tricky. When an error occurs within an `async`\nfunction, the resulting stack trace may be incomplete. This is because asynchronous calls\nintroduce \"gaps\" where the execution pauses and resumes. Across these gaps, the original call stack\ncan be lost, making it difficult to trace the error back to its source.\n\u003c/details\u003e\n\n## Features\n\nUse this package to:\n\n- **Chain errors:** Throw exceptions that wrap the original error, preserving the context of the\n  initial failure across asynchronous calls.\n- **Preserve stack traces:** Maintain complete stack traces across `async`, `await`, and `Future`\n  gaps, preventing loss of crucial call stack information.\n- **Enhance crash reporting:** Report crashes with full, chained stack traces to services like\n  Crashlytics or Sentry for better debugging.\n- **Format error output:** Print chained errors in a clear, readable format, making it easier to\n  understand the error sequence.\n- **Improve debugging:** Quickly pinpoint the root cause of errors, even in complex asynchronous\n  workflows.\n\n## Getting started\n\nFirst, add `error_trace` package to\nyour [pubspec dependencies](https://pub.dev/packages/error_trace/install).\n\nAfter that, you can import the library and use it:\n\n```dart\nimport 'package:error_trace/error_trace.dart';\n```\n\n## Usage\n\nConsider the following Dart code:\n\n```dart\nFuture\u003cvoid\u003e fetchData() async {\n  await Future.delayed(Duration(milliseconds: 100));\n  throw Exception('Failed to fetch data');\n}\n\nFuture\u003cvoid\u003e processData() async {\n  await fetchData();\n}\n\nvoid main() {\n  processData().catchError((error, stackTrace) {\n    print('Caught an error:\\n$error\\n');\n    print('Stack trace:\\n$stackTrace');\n  });\n}\n```\n\nWhen you run this code, you might expect the stack trace to show that the error originated in\n`fetchData` and was called by `processData`. However, the output might look something like this:\n\n```text\nCaught an error:\nException: Failed to fetch data\n\nStack trace:\n#0 fetchData.\u003canonymous closure\u003e (file:///path/to/your/file.dart:2:9) \u003casynchronous suspension\u003e\n#1 Future.Future.microtask.\u003canonymous closure\u003e (dart:async/future_patch.dart:187:31) \u003casynchronous suspension\u003e\n```\n\nNotice that the stack trace doesn't show that `processData` called `fetchData`. The asynchronous gap\nintroduced by `await Future.delayed` has caused the loss of that part of the call stack. This makes\nit harder to understand the sequence of events that led to the error.\n\nTo preserve the complete stack trace across asynchronous calls we transform the above code by using\n`error_trace` in the following way:\n\n```dart\nFuture\u003cvoid\u003e fetchData() async {\n  await Future.delayed(Duration(milliseconds: 100));\n  throw Exception('Failed to fetch data');\n}\n\nFuture\u003cvoid\u003e processData() async {\n  try {\n    await fetchData();\n  } catch (e, st) {\n    // Throw a TraceableException that includes the cause exception details\n    throw TraceableException(e, st, message: 'Process data exception');\n  }\n}\n\nvoid main() {\n  processData().catchError((error, stackTrace) {\n    print('Caught an error:');\n    // Use printError to print the chain of errors with the complete stack trace\n    printError(error, stackTrace);\n  });\n}\n```\n\nNow, the output might look something like this:\n\n```text\nCaught an error:\nProcess data exception (Caused by: Exception: Failed to fetch data)\n  path/to/your/file.dart 6:13  processData\n  path/to/your/file.dart 14:5  main\nCaused by: Exception: Failed to fetch data\n  path/to/your/file.dart 1:9  fetchData\n```\n\nNotice that the stack trace now shows that `processData` called `fetchData`.\n\nYou can\ncheck [trace_errors_from_async_function_example.dart](example/trace_errors_from_async_function_example.dart)\nfor a more detailed example.\n\n### Chaining exceptions\n\nTo prevent the loss of the stack trace you have to catch the exceptions that are thrown by other\nparts of the code and throw a `Traceable` that wraps the cause exceptions.\n\n`Traceable` is an interface that you can implement to create your own traceable exceptions or\nerrors. It has two properties:\n\n- `causeError`: The original error that caused this exception or error.\n- `causeStackTrace`: The stack trace of the original error.\n\n`TraceableException` and `TraceableError` are ready-to-use classes that implement the `Traceable`\ninterface. These classes extend `Exception` and `Error`, respectively:\n\n```dart\nFuture\u003cvoid\u003e main() async {\n  try {\n    await operationThatMayThrow();\n  } on Exception catch (e, st) {\n    throw TraceableException(e, st);\n  } on Error catch (e, st) {\n    throw TraceableError(e, st);\n  }\n}\n```\n\nAlso, you can extend these classes if you want to implement your own `Traceable` exceptions or\nerrors:\n\n```dart\nclass MyException extends TraceableException {\n  MyException(\n    super.causeError, // The original error that caused this exception.\n    super.causeStackTrace, // The stack trace of the original error.\n  ) : super(name: 'MyException');\n}\n\n// Or\n\nclass MyError extends TraceableError {\n  MyError(\n    String message, // A message describing the error.\n    super.causeError, // The original error that caused this error.\n    super.causeStackTrace, // The stack trace of the original error.\n  ) : super(name: 'MyError', message: message);\n}\n```\n\nThere is more info about theses classes in\nthe [API reference](https://pub.dev/documentation/error_trace/latest/error_trace/).\n\n#### Chaining using `Future` callbacks\n\nUse `Future.catchError` to chain exceptions in a code that doesn't use `async` and `await`:\n\n```dart\nFuture\u003cvoid\u003e processData() {\n  return fetchData().catchError((e, st) {\n    throw TraceableException(e, st, message: 'Process data exception');\n  });\n}\n```\n\nYou can\ncheck [trace_errors_of_unawaited_future_example.dart](example/trace_errors_of_unawaited_future_example.dart)\nfor a more detailed example.\n\n### Printing errors\n\nThe `error_trace` package provides a convenient way to print chained errors with their complete\nstack traces using the `printError` function. This function recursively traverses the chain of\n`Traceable` exceptions or errors, printing each one along with its stack trace in a clear, readable\nformat.\n\nHere's how you can use it:\n\n```dart\nvoid main() {\n  runZonedGuarded(() {\n    // Some operations that throw exceptions...\n  }, (error, stackTrace) {\n    print('Uncaught error:');\n    printError(error, stackTrace);\n  });\n}\n```\n\nIt prints the error details formated like this:\n\n```text\nFooException: Foo failed (Caused by: BarException: Bar failed (Caused by: Exception))\n  path/to/your/foo.dart 6:13   fooFunction\n  path/to/your/file.dart 14:5  main\nCaused by: BarException: Bar failed (Caused by: Exception)\n  path/to/your/bar.dart 3:3   someFunction\n  path/to/your/bar.dart 10:6  barFunction\nCaused by: Exception\n  path/to/your/another.dart 3:15  anotherFunction\n```\n\nYou can check the [API reference](https://pub.dev/documentation/error_trace/latest/error_trace/) for\nadditional formating tools.\n\n### Reporting errors\n\nThe `error_trace` package makes it easy to report chained errors to services like Firebase\nCrashlytics or Sentry.\n\n#### Reporting errors to Crashlytics\n\nYou can use `chainCauses` with Crashlytics in the following way:\n\n```dart\nFuture\u003cvoid\u003e main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  await Firebase.initializeApp();\n\n  FlutterError.onError = (errorDetails) {\n    FirebaseCrashlytics.instance.recordFlutterFatalError(\n      errorDetails.exception,\n      // Creates a [Chain] instance that includes all the causes chained\n      errorDetails.stack.chainCauses(error),\n    );\n  };\n\n  PlatformDispatcher.instance.onError = (error, stack) {\n    FirebaseCrashlytics.instance.recordError(\n      error,\n      // Creates a [Chain] instance that includes all the causes chained\n      stack.chainCauses(error),\n      fatal: true,\n    );\n    return true;\n  };\n\n  // ...\n}\n```\n\nThe `chainCauses` extension method on `StackTrace` combines multiple stack traces from a chain of\nerrors into a single `Chain` object. This object is provided by the `stack_trace` package and can be\npassed to Crashlytics because it implements `StackTrace`.\n\nYou can check a full example\nat [report_errors_to_crashlytics_example.dart](example/report_errors_to_crashlytics_example.dart).\n\nMore info on how to setup Crashlytics can be\nfound [here](https://firebase.flutter.dev/docs/crashlytics/usage).\n\n#### Reporting errors to Sentry\n\nYou can provide an `ExceptionCauseExtractor` that extracts causes from `Traceable` errors in the\nfollowing way:\n\n```dart\nclass _TraceableExtractor extends ExceptionCauseExtractor\u003cTraceable\u003e  {\n  @override\n  ExceptionCause? cause(Traceable error) {\n    return ExceptionCause(error.causeError, error.causeStackTrace);\n  }\n}\n\nFuture\u003cvoid\u003e main() async {\n  await SentryFlutter.init(\n    (options) {\n      options.addExceptionCauseExtractor(_TraceableExtractor());\n    },\n    // Init your App\n    appRunner: () =\u003e runApp(MyApp()),\n  );\n}\n```\n\nMore info on how to setup Sentry can be found [here](https://pub.dev/packages/sentry_flutter).\n\n## Additional information\n\nUnder the hood, this package uses the [stack_trace](https://pub.dev/packages/stack_trace) package to\nmanipulate and format stack trace. Take a look on it if you want to make more advanced features.\n\nYou will notice that `stack_trace` provides `Chain.capture` that also solves the problem of losing\nstack trace information in asynchronous operations. It's a good solution, however, it's not\nrecommended for production code because the performance overhead of creating new zones to capture\nthe stack trace.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fppicas%2Ferror_trace","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fppicas%2Ferror_trace","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fppicas%2Ferror_trace/lists"}