All Decisions

ADR-0007: Error Handling Philosophy (Fail Silently vs Explicit)

DateFebruary 8, 2026
CategoryDomain Logic
Tags
state-management

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.