Preserve Stack Trace
ID |
java.preserve_stack_trace |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Reliability |
Language |
Java |
Tags |
reliability |
Description
Reports throw statements inside a catch block that do not reference the caught exception anywhere in the new exception being thrown. The caught exception’s stack trace is therefore dropped, making diagnosis of the original failure much harder.
Rationale
When an exception is caught and re-wrapped, the new exception should carry the caught one as its cause — either as the trailing constructor argument (new X(msg, cause)) or via Throwable.initCause(cause). If neither reference is kept, the original stack trace is lost and the log entry for the new exception only shows the wrapper’s creation site, typically a few frames away from the real problem.
// Bad — stack trace of 'e' is gone
try {
doWork();
} catch (IOException e) {
throw new IllegalStateException("work failed");
}
Remediation
Pass the caught exception as the cause:
// Good — preserves the caller chain
try {
doWork();
} catch (IOException e) {
throw new IllegalStateException("work failed", e);
}
Or simply re-throw when no wrapping is needed:
try {
doWork();
} catch (IOException e) {
throw e;
}
If the exception type you need to throw has no (String, Throwable) constructor, chain via initCause:
try {
doWork();
} catch (IOException e) {
throw (IllegalStateException) new IllegalStateException("work failed").initCause(e);
}