Suppressed Exceptions
How try-with-resources keeps the primary exception and attaches cleanup failures — addSuppressed, getSuppressed and cause vs suppressed.
#What are Suppressed Exceptions?
A suppressed exception is an exception that occurs while closing a resource, but is not allowed to replace the original (primary) exception.
This concept was introduced in Java 7 along with try-with-resources. The goal is to preserve both exceptions instead of losing one.
#Why Were Suppressed Exceptions Introduced?
Before Java 7, consider this example:
try {
throw new RuntimeException("Main Exception");
} finally {
throw new RuntimeException("Close Exception");
}RuntimeException: Close ExceptionProblem: Main Exception is lost forever. The exception thrown from finally replaces the original exception, which makes debugging difficult.
The Problem with Resource Cleanup
try {
// Read file
throw new IOException("Read Failed");
} finally {
reader.close();
}#Java 7 Solution
With try-with-resources, Java preserves both exceptions.
The original exception remains the main exception. The cleanup exception becomes a suppressed exception.
Example
class MyResource implements AutoCloseable {
@Override
public void close() {
throw new RuntimeException("Close Failed");
}
}Usage:
try (MyResource resource = new MyResource()) {
throw new RuntimeException("Business Failed");
}RuntimeException: Business Failed
Suppressed: RuntimeException: Close FailedNotice:
- The primary exception is preserved.
- The closing exception is suppressed.
#Primary vs Suppressed Exception
#How Java Stores Suppressed Exceptions
Every Throwable contains a list of suppressed exceptions. Methods (added in Java 7):
addSuppressed(Throwable exception)
getSuppressed()getSuppressed()
try (MyResource resource = new MyResource()) {
throw new RuntimeException("Main");
} catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
System.out.println(t.getMessage());
}
}Close FailedaddSuppressed()
Java adds suppressed exceptions automatically in try-with-resources, but you can also do it manually:
Exception main = new Exception("Main");
Exception cleanup = new Exception("Cleanup");
main.addSuppressed(cleanup);
throw main;Exception: Main
Suppressed: Exception: Cleanup#Multiple Resources
try (
ResourceA a = new ResourceA();
ResourceB b = new ResourceB()
) {
throw new RuntimeException("Main");
}Closing order: ResourceB.close() → ResourceA.close(). If both close() methods throw exceptions:
- Main Exceptionprimary
- ResourceB.close()suppressed
- ResourceA.close()suppressed
#Resource Closing Flow
Real JDBC Example
try (
Connection con = dataSource.getConnection();
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery()
) {
// Business logic
}If query execution fails and closing the ResultSet also fails, Java reports the primary SQLException with the closing failure as a suppressed SQLException. Nothing is lost.
Printing Suppressed Exceptions
catch (Exception e) {
e.printStackTrace();
}RuntimeException: Main Exception
Suppressed: RuntimeException: Close ExceptionModern JVMs automatically print suppressed exceptions in stack traces.
#Suppressed vs Cause
Many developers confuse these concepts.
| Cause | Suppressed |
|---|---|
| Root reason for the exception | Additional exception during cleanup |
| One cause | Multiple suppressed exceptions |
Accessed using getCause() | Accessed using getSuppressed() |
| Used in exception chaining | Used mainly by try-with-resources |
- IOException
- Cause: Disk Full
- Suppressed: Close Failed
Exception Chaining vs Suppressed Exceptions
Exception chaining:
throw new FileUploadException("Upload Failed", e);| Relationship | Meaning |
|---|---|
| Main exception → cause | The original reason |
| Main exception → suppressed | A cleanup failure |
#Common Mistakes
Ignoring Suppressed Exceptions
Wrong:
catch (Exception e) {
e.getMessage();
}Better:
catch (Exception e) {
e.printStackTrace();
for (Throwable t : e.getSuppressed()) {
logger.error(t.getMessage());
}
}Throwing from finally
Wrong:
finally {
throw new RuntimeException();
}Prefer try-with-resources, which preserves both exceptions automatically.
#Enterprise Perspective
In enterprise applications, suppressed exceptions are commonly seen with JDBC, file I/O, Apache POI, ZIP processing, network sockets, HTTP clients and cloud SDKs.
Most frameworks rely on try-with-resources, so suppressed exceptions are handled automatically. Developers should still know how to inspect them when debugging production issues.
#Interview Questions
Q1What is a suppressed exception?
An exception thrown while closing a resource that is attached to the primary exception instead of replacing it.
Q2Why were suppressed exceptions introduced?
To preserve the original exception and avoid losing cleanup failures when using try-with-resources.
Q3Which Java version introduced suppressed exceptions?
Java 7.
Q4Which methods are used?
addSuppressed() and getSuppressed().
Q5Where are suppressed exceptions mainly used?
In try-with-resources.
Q6What is the difference between getCause() and getSuppressed()?
getCause()returns the underlying reason for an exception.getSuppressed()returns exceptions that occurred during resource cleanup.
Q7Can one exception have multiple suppressed exceptions?
Yes. Each failed resource closure can contribute another suppressed exception.
Q8Does printStackTrace() display suppressed exceptions?
Yes. Modern JVMs include suppressed exceptions in the printed stack trace.
#Best Practices
- Always prefer try-with-resources over manual resource cleanup.
- Preserve the primary exception.
- Inspect suppressed exceptions while debugging resource-related failures.
- Use exception chaining (cause) for business failures and suppressed exceptions for cleanup failures.
- Do not replace the original exception with cleanup exceptions.
#Chapter Summary
- What suppressed exceptions are and why Java introduced them
- Primary vs suppressed exceptions
- try-with-resources behaviour
addSuppressed()andgetSuppressed()- Resource closing flow and multiple resources
- Difference between suppressed exceptions and causes
- Enterprise usage