- Follow the "let it crash" principle — do not defensively handle errors your process cannot recover from; let the supervisor restart the process.
- Return `{ok, Result}` or `{error, Reason}` tuples from functions — pattern match the return value at the call site to force explicit error handling.
- Use `try Expr catch Class:Reason:Stacktrace -> ... end` only at process boundaries (e.g., `gen_server` callbacks) to log and convert unexpected exceptions.
- Use `gen_server:call/3` with a timeout and handle `{error, timeout}` — never use `infinity` timeout in production calls to external processes.
- Use `erlang:monitor(process, Pid)` before sending a message and handle `{'DOWN', Ref, process, Pid, Reason}` to detect peer process failures.
- Use `logger:error("message", #{context => Value})` with structured metadata maps at catch boundaries — avoid `io:format` in error handlers.
- Return `{stop, Reason, State}` from `gen_server` callbacks when the server encounters an unrecoverable error — the supervisor will restart it.