Abrova
☰ Docs menu · Stack traces & source maps

Stack Traces

Automatic stack trace capture for uncaught exceptions, manual captures, async errors, and native crashes — with source map support for web platforms.

Last updated: 27 Oct 2026

Stack traces show the exact sequence of function calls leading to an error — revealing WHERE it happened, HOW the code got there, and WHAT functions were called.

Automatic Stack Trace Capture#

No additional configuration needed. AbrovaTrace automatically captures stack traces from:

  • Uncaught exceptions (with captureUncaughtErrors: true)
  • Manual exception captures (with captureException())
  • Async errors (with initWithZone())
  • Platform exceptions from native code
dart
try {
  await riskyOperation();
} catch (e, stackTrace) {
  await AbrovaTrace.captureException(
    e,
    stackTrace: stackTrace, // Always include this!
    message: 'Operation failed',
    extra: {'user_id': 'user_123'},
  );
}

Reading Stack Traces#

Exception: FormatException: Invalid input

at Parser.parse (lib/parser.dart:42:15) ← where error occurred

at DataService.process (lib/data_service.dart:108:8)

at HomeScreen.loadData (lib/screens/home.dart:55:12)

at _HomeScreenState.initState (lib/screens/home.dart:23:5)

  • Top line: Where the error occurred
  • Following lines: The call stack (how the code got there)
  • File paths & line numbers: Help locate the exact issue

Platform-Specific Stack Traces#

Flutter Mobile

Full Dart stacks with line numbers and method names preserved

Flutter Web

JavaScript error stacks with browser info — may need source maps for readability

Flutter Desktop

Full debug info with complete stacks and platform details

Chrome Extension

Extension context info with Chrome version, background/popup context

Adding Context to Stack Traces#

dart
try {
  await processPayment(orderId, amount);
} catch (e, stackTrace) {
  await AbrovaTrace.captureException(
    e,
    stackTrace: stackTrace,
    message: 'Payment processing failed',
    extra: {
      'order_id': orderId,
      'amount': amount,
      'payment_method': paymentMethod,
    },
  );
}

Native Crash Stack Traces#

Native crashes are detected on the next app launch. When a crash kills the app, it can't report in real-time — so AbrovaTrace detects it on restart.

Important. Native crash capture is installed when you initialize the SDK (AbrovaTrace.initWithZone() or AbrovaTrace.init()) — no extra call is needed. AbrovaTrace.close() only flushes pending data and shuts the SDK down.

Uploading Source Maps#

For web platforms (Next.js, Flutter Web), upload .map files so production stack traces resolve to your original source files and line numbers.

Where to upload

  • Abrova Console — at console.abrova.ir → your project → Trace → Source maps & symbols. Set the release version and upload your .map files (several in one go).
  • Abrova CLI — upload from your build or CI with abrova-trace sourcemaps upload. See Upload Source Maps.
  • The Abrova desktop app will offer the same upload when it launches (coming soon).

The release version must match the release field you pass to the SDK at init — that's how the backend pairs the right map with each error.

Uploading needs the member role or higher; deleting uploaded files needs admin or owner. See Roles & Permissions.

Next.js

javascript
// next.config.js
module.exports = {
  productionBrowserSourceMaps: true,
};

After next build, you'll find the .map files next to the chunks under .next/static/chunks/. Up to 500 .map files are accepted per upload, so you can drop them all at once (non-.map files are skipped).

Flutter Web

Build with source maps enabled, then upload the single main.dart.js.map:

bash
flutter build web --source-maps

The map will be at build/web/main.dart.js.map.

Flutter Web — what to expect from resolved traces.

dart2js (the compiler that turns Dart into JavaScript) inlines aggressively in --release builds. Some frames will resolve cleanly to your .dart files. Others will resolve to framework internals (js_helper.dart, dart:async) or stay minified (a3v.$0) because the .map simply contains no mapping for those JS bytes.

This is a property of dart2js output — not the resolver. We tell you up front because most teams hit it in production and assume their setup is broken. It isn't.

Where Abrova pulls ahead is context. Enable gesture breadcrumbs (AbrovaTrace.enableGestureBreadcrumbs()) so every issue shows the widget the user tapped right before the error, plus the route, last HTTP call, and any custom breadcrumbs. Combined with the partially-resolved trace, you get a reproducible bug report.

For QA / staging only, you can force less aggressive optimization to get fully resolved traces:

bash
flutter build web --source-maps --dart2js-optimization=O1

Bundle size grows ~30% — fine for staging, not recommended for production.

Best Practices#

Always Include Stack Traces

Pass the stackTrace parameter when manually capturing exceptions

Add Meaningful Context

Include user IDs, screen names, and relevant data in the extra field

Use Release Versions

Set the release version to correlate errors with deployments

Combine with Breadcrumbs

Breadcrumbs show what user did, stack traces show where code failed

Test in Development

Enable debug: true to see stack traces in console during development

Was this page helpful?
Report a problem