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.