---
name: flutter-error-observability
description: Builds a typed Flutter error pipeline with global catch points, repository-boundary mapping, Riverpod UI states, and PostHog reporting. Use when implementing error handling, Failure or Result types, crash reporting, analytics context, retries, or unhappy-path tests.
---

# Flutter Error Handling and Observability

## Establish the pipeline

1. Install global handlers before `runApp` for Flutter framework, uncaught platform, and isolate errors.
2. Define a small sealed `Failure` hierarchy with user-safe messages.
3. Centralize raw exception translation in one `failureFrom(Object)` mapper in `core/errors/`.
4. Catch and translate infrastructure exceptions at repository boundaries.
5. Report the raw error and original stack before returning or throwing the mapped failure.
6. Let controllers expose loading, data, and failure through `AsyncValue`.
7. Render a helpful message and retry action; never render a raw exception.

## Catch at the correct boundary

- Global hooks catch defects and uncaught asynchronous failures that escaped normal flows.
- Repositories catch Dio, socket, Supabase, Firebase, parsing, and persistence exceptions they can translate.
- Controllers coordinate state; they must not duplicate infrastructure mapping.
- Views react to typed failures and trigger UI side effects through `ref.listen`.
- Catch only conditions that can be handled; allow programming `Error`s to reach global reporting.

## Choose a failure style

- Use `Result<T>` with sealed `Ok<T>` and `Err<T>` for payments, sync, destructive actions, and operations whose caller must branch explicitly.
- Throw typed `Failure`s inside flows already guarded by `AsyncNotifier` when the shorter composition is clearer.
- Pick one approach per boundary and handle every variant exhaustively.
- Use `rethrow`, never `throw e`, when preserving the original stack.

## Report once

- Depend on an `ErrorReporter` interface rather than the PostHog SDK throughout application code.
- Choose either PostHog global autocapture or manually installed global hooks for each error source; enabling both duplicates events.
- Add actionable context such as screen, operation, endpoint, app version, and severity.
- Identify users with a stable non-PII identifier.
- Remove emails, tokens, request bodies, and other sensitive values in `beforeSend`.
- Do not await reporting on UI hot paths; logging must not block recovery.

## Observe healthy behavior too

- Keep success analytics separate from error reporting unless a single telemetry facade is an intentional project convention.
- Track attempted and completed operations so failure rates can be measured.
- Attach `PosthogObserver` to GoRouter and name every route.
- Add observers to nested shell navigators when tab changes must produce screen events.

## UI behavior

- Convert a known `Failure` to its safe message and use a generic fallback for unknown errors.
- Preserve existing data during refresh when that produces a better experience.
- Pair every recoverable error with a next action: retry, reauthenticate, edit input, or go back.
- Use the shared snack, alert, and error-view factories instead of one-off Material boilerplate.

## Test checklist

- Force each repository exception and assert the expected `Failure` mapping.
- Verify the reporter receives the original error, stack, and redacted context exactly once.
- Verify controller state reaches `AsyncError` or `Err` as designed.
- Assert the view shows safe copy and the retry invokes the intended controller action.
- Exercise at least one global-handler path in integration tests.
