ADR-0007: Error Handling Philosophy (Fail Silently vs Explicit)
DateFebruary 8, 2026
CategoryDomain Logic
Context
Different errors have different implications for user experience and data integrity. Some failures (e.g., transient background jobs) should not disrupt flow, while user-facing operations (save, delete, processing actions) must surface clear feedback and recovery paths. LocusFlow's offline-first, privacy-respecting design also constrains telemetry and remote error reporting.
Constraints and triggers:
- Local-first app with optional background processing
- Limited/opt-in telemetry
- Desire for predictable UX during capture and processing flows
Decision
We will follow a hybrid philosophy:
- Explicit errors: For user-initiated, actionable operations (create, save, transform, delete), surface errors explicitly to the user with a clear, localized message and suggested recovery action. These errors should be represented in the domain layer as typed failures and mapped to UI effects for presentation.
- Fail silently (but observe): For non-actionable background tasks (non-critical indexing, low-priority background synthesis, analytics that are best-effort), do not interrupt the user flow. Log and persist a concise local record (for debugging or optional diagnostics) and surface an unobtrusive status when helpful (e.g., a sync indicator or health UI) rather than blocking UX.
Additionally:
- Use a typed error model (sealed classes) in the domain layer to avoid leaking low-level exceptions to the UI.
- Surface one-off error UI via
UiEffect streams (see ADR-0006) so errors appear as consumable events rather than persistent state unless recovery requires it.
- Map low-level exceptions to user-friendly messages and recovery actions in a centralized mapper in the domain/presentation boundary.
Rationale
- User clarity: Explicit errors for user actions prevent data loss and confusion.
- Reduced annoyance: Silent handling of benign background failures prevents unnecessary disruption.
- Privacy & control: Local logging supports diagnosis without mandatory telemetry; opt-in telemetry can augment logs when users consent.
- Consistency: A typed error model reduces ad-hoc string-based handling and improves testability.
Consequences
- Positive:
- Predictable UX: users see errors only when relevant.
- Easier testing and mapping from exception → user message.
- Downsides:
- Need discipline to correctly categorize failures as actionable vs non-actionable.
- Slight added complexity to map and translate low-level errors to domain errors and UI messages.
Alternatives Considered
- Always explicit: Surface every error to the user — rejected because it would produce noisy UX for harmless background failures.
- Always silent: Log all errors silently — rejected due to risk of silent data loss and degraded user trust for actionable failures.
Notes
- Create a lightweight
ErrorMapper at the domain/presentation boundary and a small, documented taxonomy of failure types (Validation, Persistence, Conflict, Network/IO, Unexpected).
- Revisit when adding remote sync or optional cloud features; explicit error surface rules may need extension for networked flows.