# Error handling and logging

> Debug.handle as an exception funnel, reacting to specific errors, and showing failures to the user.

Source: https://crossfly.dev/docs/best-practices/tratamento-de-erros-e-logging — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Error handling and logging

The central point is having **a single funnel** for exceptions and separating "an error the user sees"
from "an error for the log".

## The funnel: `Debug.handle(e)` and `Debug.log(...)`
```java
try {
   arriscado();
} catch (Exception e) {
   Debug.handle(e);        // logs and handles it uniformly (single funnel)
}
Debug.log("estado:", valor);   // free-form diagnostics
```
Framework animations and tasks already catch `Throwable` via `Debug.handle` internally. **Why a
funnel:** an unhandled exception **on the paint thread** takes down the frame — channeling it avoids a
crash and gives a single point to instrument.

## React to specific errors (don't swallow everything)
```java
try (SqliteDb db = SqliteDb.open("app.db")) {
   db.execute("INSERT INTO cliente(email) VALUES(?)", email);
} catch (SqliteException e) {
   if (e.code == Sqlite.CONSTRAINT) Hint.show("E-mail já cadastrado", 2000);   // 19
   else if (e.code == Sqlite.BUSY)  Hint.show("Banco ocupado, tente de novo", 2000);  // 5
   else Debug.handle(e);
}
```
`SqliteException.code` carries the SQLite code (`Sqlite.OK/BUSY/CONSTRAINT/LOCKED/...`). The same applies
to other typed results (e.g., `AuthResult.ERROR` from biometrics).

## Errors from background callbacks → show in the UI with `onUI`
Callbacks (network, GPS, BLE) run **outside** the paint thread. To notify the user, marshal with `onUI`:
```java
new Thread(() -> {
   try { sincronizar(); }
   catch (Exception e) {
      Component.onUI(() -> Hint.show("Falha ao sincronizar", 2000));   // Hint = non-blocking
      Debug.handle(e);
   }
}).start();
```
- **`Hint.show(...)`** for non-blocking notices; **`Alert`** when it requires a user decision.
- **Separate:** what the user needs to see (`Hint`/`Alert`) vs. what goes only to the log (`Debug.log`/`handle`).

## Debug flags
`Debug.traceKeyboard`, `Debug.showFPS`, `Debug.beepOnGC` help diagnose during development.

## Best practices
- **One funnel** (`Debug.handle`) for what isn't specifically handleable.
- Handle **specific** codes (`CONSTRAINT`, `BUSY`) with a message useful to the user.
- Background error → `onUI` + `Hint`/`Alert`; never touch the UI directly in the callback.

## Common mistakes
- Empty `catch (Exception e) {}` — swallows the problem.
- Showing a raw stack trace to the user (use `Hint`/`Alert` with a clear message; the stack goes to the log).
- Touching the UI from a background thread without `onUI`.

## See also
- [Dialogs and modals](/docs/ui/navigation/dialogs-and-modals) · [Background work](/docs/data-and-services/background-work)
