Tutorials

Build a pure-Dart error boundary

Configure assessment, bounded context, reporting, a root Zone, and controlled shutdown.

v0.1.0-dev.1Beginner

Build a pure-Dart error boundary

The example simulates an unhandled asynchronous failure in a catalog worker. The application classifies it as an integration outage, attaches two bounded request facts, sanitizes the report, writes it through a development Reporter, and waits for accepted work before shutdown.

The failing service never receives ErrorManager. Its uncaught error reaches the Zone already owned by the application.

01

Install the package

shell
dart pub add ark_error_manager:^0.1.0-dev.1
02

Describe the runtime

dart
const ErrorRuntimeEnvironment environment = ErrorRuntimeEnvironment(
  buildMode: ErrorBuildMode.release,
  deployment: ErrorDeploymentEnvironment.production,
  application: ErrorApplicationInfo(
    name: 'Catalog worker',
    version: '1.4.0',
    buildNumber: '87',
  ),
);

Build mode and deployment are separate: a release binary can run against staging, and a profile build can use production services.

03

Classify one application error

dart
final class ServiceUnavailableClassifier
    extends TypedErrorClassifier<ServiceUnavailableException> {
  const ServiceUnavailableClassifier();

  @override
  ErrorAssessment classifyError(
    ServiceUnavailableException error,
    ErrorOccurrence occurrence,
    ErrorRuntimeEnvironment environment,
  ) => const ErrorAssessment(
    category: ErrorCategory.integration,
    severity: ErrorSeverity.degraded,
  );
}
04

Add bounded diagnostic context

dart
final class RequestContextProvider implements ErrorContextProvider {
  const RequestContextProvider();

  @override
  ErrorContextSection collect(
    ErrorOccurrence occurrence,
    ErrorRuntimeEnvironment environment,
  ) => ErrorContextSection(
    name: 'request',
    fields: <String, Object?>{
      'method': 'GET',
      'endpoint': '/catalog',
    },
  );
}

Context is intentionally small. It does not include headers, request bodies, credentials, or complete application state.

05

Create the manager

dart
final ErrorManager manager = ErrorManager(
  configuration: ErrorManagerConfiguration(
    environment: environment,
    classifiers: const <ErrorClassifier>[
      ServiceUnavailableClassifier(),
    ],
    contextProviders: const <ErrorContextProvider>[
      RequestContextProvider(),
    ],
    reporters: const <ErrorReporter>[
      DeveloperLogErrorReporter(name: 'catalog.worker'),
    ],
  ),
);

The built-in fallback still handles every error not supported by the custom classifier.

06

Connect the application-owned Zone

dart
final captured = Completer<void>();

runZonedGuarded(
  () {
    scheduleMicrotask(() {
      throw const ServiceUnavailableException('catalog');
    });
  },
  (error, stackTrace) {
    manager.onUncaughtZoneError(error, stackTrace);
    captured.complete();
  },
);

await captured.future;

The package does not create the Zone. The application retains control over zoneValues, ZoneSpecification, and nested boundaries.

07

Close a controlled host

dart
await manager.flush();
await manager.close();

After close, the manager cannot be reused.

Follow the incident through the pipeline

  1. The Zone creates ErrorOccurrence with ErrorCaptureSource.zone.
  2. ServiceUnavailableClassifier produces integration/degraded assessment.
  3. RequestContextProvider adds only method and endpoint.
  4. The configured policy decides whether to report, present, or recover.
  5. The Sanitizer creates a separate ErrorReport.
  6. DeveloperLogErrorReporter receives the report, never the raw Incident.
  7. flush proves that all accepted work finished before close.

Run the complete linked example. Then replace the development Reporter only after reading the Security section and defining transport, retention, access, and deletion rules for the destination.

ARKTELOS

Purpose-built engineering systems for software that has to hold.