If both the `use` block and the resource's `close()` throw exceptions, which exception propagates, and what happens to the other?
answer
- block exception = primary, propagates
- close exception attached via addSuppressed
- read via throwable.suppressed
- block OK + close throws -> close propagates
- same model as Java try-with-resources
basics
~10 sThe error from your block wins and is thrown. The error from closing is attached to it as a 'suppressed' exception so you don't lose it, but it doesn't replace the original.
solid answer
~30 s`use` prioritises the **primary** exception (the one from the block). If the block throws and then `close()` also throws while unwinding, `use` does not let the close-exception mask the original: it records the close-exception via `Throwable.addSuppressed(...)` on the primary, then rethrows the primary. You can later read it with `primary.suppressed` (the `suppressedExceptions` array). If the block succeeds but `close()` throws, that close-exception propagates normally (there is nothing to suppress). This mirrors Java try-with-resources semantics. The behaviour relies on `addSuppressed`, available on JDK 7+; the `AutoCloseable.use` overload and suppression were enabled accordingly.
code
kotlin · 6 linestry {
closeable.use { throw RuntimeException("work failed") } // primary
} catch (e: Exception) {
// e.message == "work failed"; e.suppressed holds any close() failure
e.suppressed.forEach { println("suppressed: $it") }
}go deeper
Knows the block's error is the one you see; vague on suppression details.
States that the block exception is primary and the close exception is added as suppressed, not lost.
Explains the JDK addSuppressed mechanism and when a close-only failure surfaces; warns about durability of writes.
Designs error-handling policy for resources whose close can fail (e.g. flush-on-close) and ensures such failures aren't dropped.
## The two failure points A `use` call has two places that can throw: 1. the **block** (your code), and 2. the **`close()`** call in the finally. ## Rule: the block's exception is primary If the block throws, that exception is the **primary** one and the one that ultimately propagates out of `use`. This matters because the original failure is usually the diagnostically important one (e.g. a parse error), and you do not want it hidden by a noisy close-time failure. ## Suppression, not loss If `close()` also throws while the primary is unwinding, Kotlin does **not** discard the close-exception. It calls `primary.addSuppressed(closeException)` so the secondary is attached to the primary: ```kotlin try { resource.use { throw IllegalStateException("primary") } } catch (e: Exception) { println(e.message) // "primary" println(e.suppressed.joinToString()) // includes the close exception } ``` `Throwable.addSuppressed` and the `suppressed`/`suppressedExceptions` accessor are JDK 7+ features; this is exactly the model Java's try-with-resources uses. ## What `use` roughly does ```kotlin public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R { var exception: Throwable? = null try { return block(this) } catch (e: Throwable) { exception = e throw e } finally { when { this == null -> {} exception == null -> close() // normal path: close may throw and propagate else -> try { close() } catch (closeEx: Throwable) { exception.addSuppressed(closeEx) // attach, do not replace } } } } ``` ## If only `close()` throws When the block succeeds, `exception` is `null`, so `close()` is called outside any catch and its exception propagates directly — there is no primary to suppress under. ## Practical implication Never assume a clean `use` means the resource flushed/closed without error: a close-time `IOException` (e.g. a failed flush to disk) can still surface. If close failures are meaningful (a write that must be durable), catch them explicitly.
- How do you retrieve the suppressed exception later?From the primary `Throwable` via its `suppressed` property (Java `getSuppressed()` / `suppressedExceptions`).
- What if only `close()` throws and the block succeeded?That close exception propagates out of `use` normally — there is no primary, so nothing is suppressed.
saying these in an interview costs you the question
- Says the close() exception replaces/masks the block exception
- Thinks the close exception is silently swallowed and lost
- Believes a successful block guarantees close() cannot throw
- Unaware of addSuppressed / suppressed exceptions
- Claims `use` merges both into one message