{"record":{"id":"5dc85ed0b5d13867","repo":"apache/iceberg","slug":"unknown-exception-in-finally-block","errorCode":null,"errorMessage":"Unknown exception in finally block","messagePattern":"Unknown exception in finally block","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"warning","filePath":"api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java","lineNumber":132,"sourceCode":"      tryThrowAs(failure, e2Class);\n      tryThrowAs(failure, e3Class);\n      tryThrowAs(failure, RuntimeException.class);\n      throw new RuntimeException(\"Unknown throwable\", failure);\n\n    } finally {\n      if (finallyBlock != null) {\n        try {\n          finallyBlock.run();\n        } catch (Exception e) {\n          if (failure != null) {\n            LOG.warn(\"Suppressing failure in finally block\", e);\n            failure.addSuppressed(e);\n          } else {\n            tryThrowAs(e, e1Class);\n            tryThrowAs(e, e2Class);\n            tryThrowAs(e, e3Class);\n            tryThrowAs(e, RuntimeException.class);\n            throw new RuntimeException(\"Unknown exception in finally block\", e);\n          }\n        }\n      }\n    }\n  }\n\n  private static <E extends Exception> void tryThrowAs(Throwable failure, Class<E> excClass)\n      throws E {\n    if (excClass.isInstance(failure)) {\n      throw excClass.cast(failure);\n    }\n  }\n}\n","sourceCodeStart":114,"sourceCodeEnd":146,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java#L114-L146","documentation":"ExceptionUtil.runSafely's finally-block fallback: when the finallyBlock throws an exception while the main block succeeded (failure == null) and that exception matches none of the declared exception classes or RuntimeException, it is wrapped in RuntimeException(\"Unknown exception in finally block\"). If a primary failure existed, the finally exception is suppressed instead of wrapped.","triggerScenarios":"A finallyBlock (e.g. resource cleanup like closing streams/files) throws a checked exception not declared in runSafely's exception class list, while the main block completed successfully.","commonSituations":"Cleanup code closing custom AutoCloseables that throw checked exceptions (e.g. IOException from a Closeable) when runSafely was parameterized only for other exception types.","solutions":["Unwrap e.getCause() to get the original cleanup exception","Add the cleanup exception's class (e.g. IOException.class) to runSafely's declared exception classes","Make the finallyBlock swallow cleanup errors (log and continue) so they never propagate","Use IOUtils.closeQuietly-style helpers inside the finally block"],"exampleFix":"// before\nExceptionUtil.runSafely(block, catchB, () -> stream.close(), RuntimeException.class); // IOException wrapped\n// after\nExceptionUtil.runSafely(block, catchB, () -> stream.close(), IOException.class, RuntimeException.class);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  ExceptionUtil.runSafely(block, catchBlock, finallyBlock, E1.class, E2.class, E3.class);\n} catch (RuntimeException e) {\n  if (\"Unknown exception in finally block\".equals(e.getMessage()) && e.getCause() != null) {\n    handleCleanupFailure(e.getCause());\n  } else {\n    throw e;\n  }\n}","preventionTips":["Include cleanup-related exception classes (e.g. IOException) in runSafely's declared exceptions","Log-and-continue inside finallyBlock instead of letting cleanup errors propagate","Use closeQuietly-style helpers for cleanup that should not mask primary results","Remember: a finally exception with a primary failure becomes suppressed, not wrapped"],"tags":["java","exception-handling","finally-block","resource-cleanup"],"backgroundTag":"unexpected-response-shape","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}