Preserve Stack Trace
ID |
kotlin.preserve_stack_trace |
Severity |
low |
Remediation Complexity |
trivial |
Remediation Risk |
low |
Remediation Effort |
low |
Resource |
Best Practice |
Language |
Kotlin |
Tags |
error-handling, exception |
Description
Reports catch blocks that wrap and re-throw an exception while dropping its cause. A
common pattern is catch (e: X) { throw NewException(e.message) }: the new exception
carries the original message but not the original stack trace, making downstream
diagnosis significantly harder.
Rationale
When an exception is re-thrown as a different type, the original throwable should be
attached as the cause so that the chained stack trace survives. Java’s
Throwable(message, cause) constructor and Kotlin’s standard exceptions all accept a
cause; failing to use it silently truncates the diagnostic information that the caught
exception was about to provide.
// Bad — cause lost
try { ... } catch (e: IOException) {
throw RuntimeException(e.message) // FLAW
}
// Good — cause preserved
try { ... } catch (e: IOException) {
throw RuntimeException(e.message, e) // OK
}
try { ... } catch (e: IOException) {
throw RuntimeException("wrapped", e) // OK
}
Remediation
When wrapping an exception, always pass the caught exception as the cause argument
(typically the second constructor argument). If the wrapping is intentional and the
cause is not needed, document the choice with a comment.