Give important failures meaningful names
Custom exceptions represent application-specific failure categories. A caller can catch a named exception without examining fragile error-message strings.
Build a small hierarchy
For example, an order system might distinguish insufficient inventory from an invalid order state. Keep the hierarchy focused on cases where callers genuinely need different handling.
Preserve useful context
Exception messages should explain what happened without exposing secrets. When translating a lower-level failure into a higher-level application error, exception chaining can preserve the original cause for diagnostics.
Practice: create separate exceptions for invalid order state and insufficient inventory and handle them differently in a service function.