{"record":{"id":"e72c2a9942b1d860","repo":"apache/iceberg","slug":"suppressing-failure-in-finally-block","errorCode":null,"errorMessage":"Suppressing failure in finally block","messagePattern":"Suppressing failure in finally block","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java","lineNumber":125,"sourceCode":"        } catch (Exception e) {\n          LOG.warn(\"Suppressing failure in catch block\", e);\n          failure.addSuppressed(e);\n        }\n      }\n\n      tryThrowAs(failure, e1Class);\n      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    }","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java#L107-L143","documentation":"ExceptionUtil.runSafely() runs a finallyBlock after the guarded operation; if the finally block throws while a primary failure already exists, this warning is logged and the finally exception is attached as suppressed to the primary failure. If no primary failure exists, the finally exception is instead rethrown as e1Class/e2Class/e3Class or RuntimeException. The suppression prevents the finally/cleanup error from masking the original root cause.","triggerScenarios":"The finallyBlock.run() supplied to ExceptionUtil.runSafely(...) threw while the guarded body had already failed (failure != null) — e.g. cleanup (close, commit telemetry, release locks) executed during an error path itself threw an exception.","commonSituations":"Closing writers or releasing resources in a finally block after the main operation already failed, where the close also fails (broken connection, missing file); cleanup code that assumes the happy path succeeded.","solutions":["Fix the primary failure reported alongside this warning — it is the root cause; the finally error is secondary.","Inspect the suppressed exception in the logs to see why the finally block failed and harden that cleanup code.","Make finallyBlock idempotent and failure-tolerant (guard close/release calls with try-catch or null/state checks).","If the finally exception is the ONLY failure, it will be rethrown — fix that operation directly since it's then the real error."],"exampleFix":"// before\nExceptionUtil.runSafely(...).finallyBlock(() -> {\n  writer.close(); // throws if writer is in broken state\n});\n\n// after\nExceptionUtil.runSafely(...).finallyBlock(() -> {\n  try {\n    writer.close();\n  } catch (Exception e) {\n    LOG.warn(\"Failed to close writer in finally\", e);\n  }\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Finally-block failures are suppressed when a primary failure exists; inspect suppressed exceptions.\ntry {\n  operation.run();\n} catch (Exception e) {\n  LOG.error(\"Primary failure: {}\", e.getMessage(), e);\n  for (Throwable s : e.getSuppressed()) {\n    LOG.error(\"Suppressed (finally block): {}\", s.getMessage(), s);\n  }\n  throw e;\n}","preventionTips":["Make finallyBlock cleanup idempotent and guarded with internal try-catch.","Never let close()/release() in finally assume the happy path succeeded.","Log getSuppressed() to surface hidden finally failures.","If no primary failure exists, the finally exception is rethrown — ensure that operation is itself robust."],"tags":["exception-handling","suppressed-exception","finally-block","cleanup","iceberg"],"backgroundTag":"suppressed-cleanup-exception","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}