Throwing Exception From Finally

ID

kotlin.throwing_exception_from_finally

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Kotlin

Tags

control-flow, exception, finally

Description

Reports throw expressions inside finally blocks. A throw executed in finally silently masks any exception that may be propagating from the corresponding try body. The caller sees only the new exception, with no indication that the original failure occurred.

Rationale

// Bad — exception from parse() is lost
fun load(): Int {
    try {
        return parse()
    } finally {
        throw IllegalStateException("cleanup failed")  // FLAW
    }
}

// OK — finally only performs cleanup
fun load(): Int {
    try {
        return parse()
    } finally {
        cleanup()
    }
}

Masking exceptions in finally hides root causes, complicates diagnosis and turns reproducible failures into intermittent ones.

Remediation

  • Keep finally blocks limited to cleanup logic that does not throw.

  • If a cleanup failure must be signalled, log it and let the original exception propagate, or attach the cleanup failure as a suppressed exception via addSuppressed(…​).

  • Throws inside lambdas / local functions nested in the finally are not reported because they stay confined to the nested scope.