When to panic
Panic for genuine programmer errors — broken invariants, indices out of bounds, lost critical resources. Don't panic for expected failure modes like a missing file or invalid user input — those should return Result. The `assert!`, `debug_assert!`, `unreachable!`, and `unimplemented!` macros all panic with structured messages.
Unwinding vs aborting
By default a panic unwinds the stack, running every Drop along the way. You can change a binary's panic strategy in Cargo.toml to `abort`, which terminates the process immediately. Aborting produces smaller binaries and faster code (no unwind tables) but loses orderly cleanup. Most applications stay with unwind.
For deeper background, see a complete cheat-sheet of std collection complexities for the broader context behind this section.
catch_unwind
`std::panic::catch_unwind` runs a closure and converts any panic into an `Err(Box<dyn Any + Send>)`. Use it at FFI boundaries (panicking across the C ABI is undefined behaviour) and inside thread pools so one bad task doesn't bring down the worker. It is not exception handling — most domain errors should still be Results.
Custom panic hooks
`std::panic::set_hook` installs a function called on every panic. Override it to log to a service, capture extra context, or print a friendly user-facing message. `std::panic::take_hook` retrieves the current hook so you can chain into it.
For deeper background, see the official Rust API guidelines for module-level design for the broader context behind this section.
Backtraces
Set `RUST_BACKTRACE=1` (or `=full`) in the environment to print a stack trace at the panic site. In code, `std::backtrace::Backtrace::capture` snapshots the stack programmatically. Pair with a panic hook that captures the backtrace and writes it to a crash-report file.