At the application functionality level the sole purpose of user-defined throwable classes (descendants of Throwable) is to serve as a marker of an exceptional condition.
Most of the otherwise useful logic - recording stack-traces, recording the underlying cause has already been implemented in the lower levels of the throwable hierarchy. These are the features especially useful on the non-functional levels of the application - monitoring (logging) being one of them.
The only reason to introduce a user exception is an ability to distinguish the problem that has occurred - either sooner in the try { } catch clause or in the log later.
Hence the resolution - a user-defined throwable should not contain any extra logic i.e. only contain constructors that delegate to their parent.
This makes any user-defined throwable represent exactly one design concern - their distinct (yet polymorphic) type.
Any logic like message enhancement and localization, parameter substitution, etc. should instead be done in separate helper classes, where it may be combined with transaction management (rollback), logging and actual exception creation.
This separation also allows one to create and throw an exception without any of these additional actions performed if so desired simply by not using the helper class.