You can catch most panics using catch_unwind, but there are some rare situations where a panic will abort the program without recourse. In particular, any panic that fires while another is being handled is uncatchable, and there’s also a Cargo setting that makes all panics uncatchable.
Note that it's theoretically (and practically) possible to throw a value as panic payload which panics when dropped. Catching such a panic may cause a further panic once the payload is dropped. This can cause soundness issues if you really intend to catch every unwinding panic. See #86027.
Note that panics in Rust (caught with catch_unwind if the panics are unwinding panics) are only meant for serious errors and/or bugs. Normal errors don't unwind the stack but just return from a fuction or method.
You can use return types like Result<T, Box<dyn std::error::Error>> or the anyhow crate to specify return types that contain arbitrary errors. The ? operator can escalate any error to the next function on the stack.
In that case you can handle errors in the outermost function simply by examining the Result that is returned by the function you called.