google/guava · error · RuntimeException

failure during tearDown

Error message

failure during tearDown

What it means

TearDownStack.runTearDown() runs each registered TearDown in LIFO order. If a callback throws a checked exception, it is wrapped in a RuntimeException("failure during tearDown", cause) because TearDown.tearDown() declares no checked exceptions. Unchecked throwables are rethrown as-is; later failures are attached via addSuppressed.

Source

Thrown at android/guava-testlib/src/com/google/common/testing/TearDownStack.java:105

    }
    for (TearDown tearDown : stackCopy) {
      try {
        tearDown.tearDown();
      } catch (Throwable t) {
        if (suppressThrows) {
          logger.log(Level.INFO, "exception thrown during tearDown", t);
        } else {
          if (exception == null) {
            exception = t;
          } else {
            exception.addSuppressed(t);
          }
        }
      }
    }
    if (exception != null) {
      throwIfUnchecked(exception);
      throw new RuntimeException("failure during tearDown", exception);
    }
  }
}

View on GitHub (pinned to 94f39958ba)

Solutions

  1. Catch checked exceptions inside tearDown() and handle/log them so they never escape the callback.
  2. Re-throw as an unchecked exception (e.g. RuntimeException) from within tearDown() if the failure must surface — unchecked throwables propagate without wrapping.
  3. Construct the stack with suppressThrows=true if you want failures logged (Level.INFO) instead of thrown.
  4. Prefer try-with-resources / AutoCloseable outside the stack for resources with checked-exception close().

Example fix

// before
stack.addTearDown(() -> {
  socket.close(); // throws IOException -> wrapped RuntimeException
});

// after
stack.addTearDown(() -> {
  try { socket.close(); }
  catch (IOException e) { throw new RuntimeException(e); }
});
Defensive patterns

Strategy: try-catch

Validate before calling

// Keep checked exceptions inside tearDown; never let them escape the callback.
stack.addTearDown(() -> {
  try { resource.close(); }
  catch (IOException e) { /* log or rethrow unchecked */ }
});

Try / catch

// runTearDown wraps checked exceptions as RuntimeException; if you must drive
// it, unwrap the cause to inspect the original failure.
try {
  stack.runTearDown();
} catch (RuntimeException e) {
  Throwable c = e.getCause(); // the real checked exception
  ...
}

Prevention

When it happens

Trigger: A TearDown.tearDown() implementation throws a checked exception (e.g. IOException from closing a stream, SQLException). The wrapper is thrown at the end of runTearDown() after all callbacks have been attempted.

Common situations: Cleanup callbacks performing I/O, JDBC, or network teardown that can fail; using TearDownStack where callbacks were written without internal try-catch.

Related errors


AI-assisted analysis of google/guava@94f39958ba (2026-08-13). Data as JSON: /api/errors/f9c3372dfccb1ab4. Report an issue: GitHub.