DevNotes
Support
Exception Handling · Chapter 07

Suppressed Exceptions

How try-with-resources keeps the primary exception and attaches cleanup failures — addSuppressed, getSuppressed and cause vs suppressed.

◷ 5 min read§ 13 sections? 8 interview questions{ } 14 code examples

#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:

Java
try {
    throw new RuntimeException("Main Exception");
} finally {
    throw new RuntimeException("Close Exception");
}
Output
RuntimeException: Close Exception

Problem: Main Exception is lost forever. The exception thrown from finally replaces the original exception, which makes debugging difficult.

The Problem with Resource Cleanup

Java
try {
    // Read file
    throw new IOException("Read Failed");
} finally {
    reader.close();
}
Read Failed
close()
close() throws IOException
Which exception should Java report? Before Java 7: the close() exception — the original disappeared

#Java 7 Solution

With try-with-resources, Java preserves both exceptions.

Primary exception
+ Suppressed exception
Both available

The original exception remains the main exception. The cleanup exception becomes a suppressed exception.

Example

Java
class MyResource implements AutoCloseable {
    @Override
    public void close() {
        throw new RuntimeException("Close Failed");
    }
}

Usage:

Java
try (MyResource resource = new MyResource()) {
    throw new RuntimeException("Business Failed");
}
Output (simplified)
RuntimeException: Business Failed
    Suppressed: RuntimeException: Close Failed

Notice:

  • The primary exception is preserved.
  • The closing exception is suppressed.

#Primary vs Suppressed Exception

Business logic
Business exception thrownprimary
close() runs
Close exception thrown
Attached as suppressed

#How Java Stores Suppressed Exceptions

Every Throwable contains a list of suppressed exceptions. Methods (added in Java 7):

Java
addSuppressed(Throwable exception)
getSuppressed()

getSuppressed()

Java
try (MyResource resource = new MyResource()) {
    throw new RuntimeException("Main");
} catch (Exception e) {
    for (Throwable t : e.getSuppressed()) {
        System.out.println(t.getMessage());
    }
}
Output
Close Failed

addSuppressed()

Java adds suppressed exceptions automatically in try-with-resources, but you can also do it manually:

Java
Exception main = new Exception("Main");
Exception cleanup = new Exception("Cleanup");

main.addSuppressed(cleanup);

throw main;
Output (simplified)
Exception: Main
    Suppressed: Exception: Cleanup

#Multiple Resources

Java
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
Both cleanup failures are preserved

#Resource Closing Flow

Create resource
Execute try block
Primary exception? → Yes
Close resources
close() exception?
add as suppressed
nothing extra
Throw primary exception

Real JDBC Example

Java
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

Java
catch (Exception e) {
    e.printStackTrace();
}
Output (simplified)
RuntimeException: Main Exception
    Suppressed: RuntimeException: Close Exception

Modern JVMs automatically print suppressed exceptions in stack traces.

#Suppressed vs Cause

Many developers confuse these concepts.

CauseSuppressed
Root reason for the exceptionAdditional exception during cleanup
One causeMultiple suppressed exceptions
Accessed using getCause()Accessed using getSuppressed()
Used in exception chainingUsed mainly by try-with-resources
  • IOException
    • Cause: Disk Full
    • Suppressed: Close Failed
All three pieces of information can coexist

Exception Chaining vs Suppressed Exceptions

Exception chaining:

Java
throw new FileUploadException("Upload Failed", e);
RelationshipMeaning
Main exception → causeThe original reason
Main exception → suppressedA cleanup failure

#Common Mistakes

Ignoring Suppressed Exceptions

Wrong:

Java
catch (Exception e) {
    e.getMessage();
}

Better:

Java
catch (Exception e) {
    e.printStackTrace();
    for (Throwable t : e.getSuppressed()) {
        logger.error(t.getMessage());
    }
}

Throwing from finally

Wrong:

Java
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() and getSuppressed()
  • Resource closing flow and multiple resources
  • Difference between suppressed exceptions and causes
  • Enterprise usage