ark_error_manager 0.1.0-dev.1
ark_error_manager: ^0.1.0-dev.1 copied to clipboard
Centralized, policy-driven error management for Dart applications.
Ark Error Manager #
Centralized, policy-driven error management for Dart applications.
Ark Error Manager gives an application one explicit error-processing boundary
without turning the manager into a dependency of every UseCase, Presenter,
repository, data source, or service. The application owns one manager at its
composition root and connects the runtime boundaries it actually uses: a root
Dart Zone, child isolates, and, through ark_error_manager_flutter, Flutter's
framework and platform hooks.
Русская версия
0.1.0-dev.1is a prerelease. The central pipeline, sanitization boundary, lifecycle, and Flutter adapter are implemented and tested, but public API details may change before the first stable release.
Why this package exists #
Scattered try/catch blocks can recover a local operation, but they do not
provide an application-wide answer to these questions:
- how serious is the failure for the running application;
- which stable category should appear in diagnostics;
- which build and deployment environment produced it;
- what information is safe to persist or transmit;
- whether the user needs a passive notice or an interrupting presentation;
- whether an application scope must be reset;
- what should happen when an error reporter fails while reporting an error.
Ark Error Manager separates these decisions into typed roles. It does not use string categories, does not infer severity from the capture source, and does not send the original error object to external reporters.
Architectural boundary #
Application composition root
├── owns ErrorManager
├── connects root Zone
├── connects child-isolate listeners
└── optionally connects Flutter global hooks
│
▼
one ordered error pipeline
│
┌────────┼─────────┐
▼ ▼ ▼
reporters presenter recovery
Feature code throws typed exceptions or exposes expected failures through its
normal business state. It does not request ErrorManager from DI and does not
store the manager in Model, Presenter, Repository, or UseCase.
An expected negative business result is not automatically an exceptional failure. Validation, rejection, and other normal outcomes should remain in a typed Result or business state. The manager handles failures that need an application-level diagnostic, presentation, or recovery decision.
Installation #
dependencies:
ark_error_manager: ^0.1.0-dev.1
import 'package:ark_error_manager/ark_error_manager.dart';
Minimal Dart bootstrap #
The application creates the Zone. The manager only provides a compatible uncaught-error callback.
import 'dart:async';
import 'package:ark_error_manager/ark_error_manager.dart';
void main() {
final ErrorManager manager = ErrorManager(
configuration: ErrorManagerConfiguration(
environment: const ErrorRuntimeEnvironment(
buildMode: ErrorBuildMode.release,
deployment: ErrorDeploymentEnvironment.production,
application: ErrorApplicationInfo(
name: 'Example application',
version: '1.4.0',
buildNumber: '87',
),
),
reporters: const <ErrorReporter>[
DeveloperLogErrorReporter(),
],
),
);
runZonedGuarded(
() {
startApplication();
},
manager.onUncaughtZoneError,
);
}
ErrorManager deliberately has no runGuarded method. The application keeps
control over Zone creation, zoneValues, ZoneSpecification, and nested
runtime boundaries.
Error assessment #
ErrorCategory #
ErrorCategory is a closed enum:
domain— an unexpected domain-invariant violation;application— application orchestration failed;infrastructure— storage, network, or another technical resource failed;integration— a third-party service, SDK, or plugin failed;framework— Dart, Flutter, or another framework reported a contract error;configuration— required configuration is invalid or incomplete;lifecycle— initialization, shutdown, or disposal failed;unknown— no more precise category was established.
Applications extend classification through ErrorClassifier, not by adding
uncontrolled string values to the category vocabulary:
final class SessionExpiredClassifier
extends TypedErrorClassifier<SessionExpiredException> {
const SessionExpiredClassifier();
@override
ErrorAssessment classifyError(
SessionExpiredException error,
ErrorOccurrence occurrence,
ErrorRuntimeEnvironment environment,
) {
return const ErrorAssessment(
category: ErrorCategory.application,
severity: ErrorSeverity.critical,
);
}
}
Classifiers are ordered. The first supporting classifier owns the occurrence;
the built-in fallback produces unknown and critical.
ErrorSeverity #
Severity describes application impact, not where the error was caught:
recoverable— one operation failed, but state remains consistent;degraded— the application continues with reduced functionality;critical— a significant scope or subsystem needs controlled recovery;fatal— the process or isolate cannot safely continue.
Derived properties such as applicationMayContinue and
requiresApplicationTermination are provided by
ErrorSeverityAssessment. There is no independent isFatal flag that can
contradict the enum.
ErrorCaptureSource is a separate dimension: zone, framework, platform,
isolate, or reported. A critical error remains critical regardless of the
boundary that observed it.
The processing pipeline #
One accepted occurrence moves through these stages in order:
- classifiers produce
ErrorAssessment; - context providers collect structured runtime context;
- policy creates
ErrorActionPlan; - sanitizer creates a report safe for reporters;
- independent reporters record the sanitized report;
- an optional presenter performs the user-facing action;
- an optional recovery controller performs application-level recovery;
- observers receive lifecycle notifications.
Occurrences are processed sequentially by one manager instance. A slow report cannot reorder a later incident ahead of an earlier one.
Pipeline components are isolated. If one reporter throws, the remaining
reporters still run. Pipeline failures go to ErrorPipelineFailureHandler and
are never submitted back to the same manager recursively.
Reporting, presentation, and recovery #
ErrorPolicy returns one explicit ErrorActionPlan:
const ErrorActionPlan(
reporting: ErrorReportingDirective.record,
presentation: ErrorPresentationDirective.blocking,
recovery: ErrorRecoveryDirective.resetScope,
)
These actions are separate because they answer different questions:
- reporting decides whether diagnostics must be persisted or transmitted;
- presentation decides what the active user should see;
- recovery decides how the application restores a safe state.
The built-in StandardErrorPolicy records every accepted occurrence, adapts
presentation intensity to severity and build mode, and requests termination
only for fatal. Applications can replace it with a policy that also inspects
the concrete error type, category, environment, or operation.
Reporters receive ErrorReport, not ErrorIncident. The report does not
contain the original error object or source-specific raw details. Presenter and
recovery remain local to the application and receive the raw incident when
they need typed decisions.
Runtime environment #
Two independent values describe the runtime:
ErrorBuildMode:debug,profile, orrelease;ErrorDeploymentEnvironment:development,staging,production, ortest.
Compilation mode and deployment target are not interchangeable. A profile build can run against staging, and a release build can run in an internal development environment.
ErrorApplicationInfo adds the application name, version, optional build
number, and package identifier. Flutter build-mode detection is provided by
ark_error_manager_flutter.
Security boundary #
StrictErrorSanitizer is the default sanitizer. It:
- masks fields whose names indicate authorization, cookies, passwords, secrets, tokens, API keys, or sessions;
- recursively sanitizes nested maps and iterables;
- sanitizes the operation and stack-trace text;
- replaces the original error message with its runtime type in release mode.
Custom reporters must not receive ErrorIncident. Keep raw request headers,
cookies, credentials, complete request bodies, and personal data out of
ErrorContextSection. Sanitization is a safety boundary, not permission to
collect everything first.
See Security and privacy for the complete model.
Handled errors #
A global boundary cannot observe an error that local code catches and fully consumes. There are only three honest outcomes:
- the local boundary recovers and the error needs no global processing;
- it transforms or rethrows the failure so that normal propagation continues;
- it deliberately reports the caught error through
handleErrororcaptureError.
The third option belongs at a real integration boundary that must suppress
propagation. It is not a reason to inject ErrorManager into every business
object.
Child isolates #
Root-isolate hooks do not receive errors from child isolates automatically. Attach one bridge when the application creates an isolate:
final Isolate worker = await Isolate.spawn(startWorker, configuration);
final IsolateErrorManagerBinding binding = IsolateErrorManagerBinding(
isolate: worker,
manager: manager,
)..attach();
// Before releasing ownership of the isolate:
binding.detach();
The bridge is owned beside the isolate. Worker code does not import or look up the manager.
Lifecycle #
captureErroraccepts work without requiring the caller to await processing;handleErrorcompletes after all planned actions finish;flushwaits for all currently accepted occurrences;closestops accepting new work and drains the existing pipeline;- repeated work after
closeis rejected.
Call flush before a controlled shutdown when reports must finish. Call
close when the application permanently releases the manager.
Package relationships #
Ark Error Manager has no dependency on UseCase Forge, Ark MVP, Ark DI, or Ark Data Layer. Those packages already propagate unexpected errors through Stream, Flutter, or Zone boundaries. Application-specific error types can be classified centrally without introducing reverse dependencies between packages.
Further reading #
- Architecture
- Security and privacy
- Integration recipes
- Runnable examples
- API reference
- Issue tracker
License #
Apache License 2.0. See LICENSE and NOTICE.