{"record":{"id":"f9c3372dfccb1ab4","repo":"google/guava","slug":"failure-during-teardown","errorCode":null,"errorMessage":"failure during tearDown","messagePattern":"failure during tearDown","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"android/guava-testlib/src/com/google/common/testing/TearDownStack.java","lineNumber":105,"sourceCode":"    }\n    for (TearDown tearDown : stackCopy) {\n      try {\n        tearDown.tearDown();\n      } catch (Throwable t) {\n        if (suppressThrows) {\n          logger.log(Level.INFO, \"exception thrown during tearDown\", t);\n        } else {\n          if (exception == null) {\n            exception = t;\n          } else {\n            exception.addSuppressed(t);\n          }\n        }\n      }\n    }\n    if (exception != null) {\n      throwIfUnchecked(exception);\n      throw new RuntimeException(\"failure during tearDown\", exception);\n    }\n  }\n}\n","sourceCodeStart":87,"sourceCodeEnd":109,"githubUrl":"https://github.com/google/guava/blob/94f39958baf7ad51ddf9c70e406ed6b188194daa/android/guava-testlib/src/com/google/common/testing/TearDownStack.java#L87-L109","documentation":"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.","triggerScenarios":"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.","commonSituations":"Cleanup callbacks performing I/O, JDBC, or network teardown that can fail; using TearDownStack where callbacks were written without internal try-catch.","solutions":["Catch checked exceptions inside tearDown() and handle/log them so they never escape the callback.","Re-throw as an unchecked exception (e.g. RuntimeException) from within tearDown() if the failure must surface — unchecked throwables propagate without wrapping.","Construct the stack with suppressThrows=true if you want failures logged (Level.INFO) instead of thrown.","Prefer try-with-resources / AutoCloseable outside the stack for resources with checked-exception close()."],"exampleFix":"// before\nstack.addTearDown(() -> {\n  socket.close(); // throws IOException -> wrapped RuntimeException\n});\n\n// after\nstack.addTearDown(() -> {\n  try { socket.close(); }\n  catch (IOException e) { throw new RuntimeException(e); }\n});","handlingStrategy":"try-catch","validationCode":"// Keep checked exceptions inside tearDown; never let them escape the callback.\nstack.addTearDown(() -> {\n  try { resource.close(); }\n  catch (IOException e) { /* log or rethrow unchecked */ }\n});","typeGuard":null,"tryCatchPattern":"// runTearDown wraps checked exceptions as RuntimeException; if you must drive\n// it, unwrap the cause to inspect the original failure.\ntry {\n  stack.runTearDown();\n} catch (RuntimeException e) {\n  Throwable c = e.getCause(); // the real checked exception\n  ...\n}","preventionTips":["Catch all checked exceptions inside each TearDown.tearDown() body.","Re-throw unchecked exceptions if the failure must propagate.","Use suppressThrows=true when you want failures logged rather than thrown.","Prefer try-with-resources for resources whose close() throws checked exceptions."],"tags":["guava","testing","teardown","lifecycle","exception-wrapping"],"backgroundTag":null,"analyzedSha":"94f39958baf7ad51ddf9c70e406ed6b188194daa","analyzedAt":"2026-08-13T22:50:30.265Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}