{"record":{"id":"f1ef8d7ceaef591e","repo":"apache/iceberg","slug":"suppressing-failure-in-catch-block","errorCode":null,"errorMessage":"Suppressing failure in catch block","messagePattern":"Suppressing failure in catch block","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java","lineNumber":108,"sourceCode":"      CatchBlock catchBlock,\n      FinallyBlock finallyBlock,\n      Class<? extends E1> e1Class,\n      Class<? extends E2> e2Class,\n      Class<? extends E3> e3Class)\n      throws E1, E2, E3 {\n\n    Throwable failure = null;\n    try {\n      return block.run();\n\n    } catch (Throwable t) {\n      failure = t;\n\n      if (catchBlock != null) {\n        try {\n          catchBlock.run(failure);\n        } 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);","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java#L90-L126","documentation":"ExceptionUtil.runSafely() executes a caller-supplied catchBlock after a failure occurs; if that catch block itself throws, this warning is logged and the catch-block exception is attached via Throwable.addSuppressed to the original failure, which is then rethrown as e1Class/e2Class. The library suppresses it so the original root-cause failure is not masked by a secondary error in cleanup/handling code.","triggerScenarios":"A try block passed to ExceptionUtil.runSafely(...) failed, and the provided catchBlock.run(failure) also threw an exception — e.g. the catch block attempts to abort a writer, roll back a transaction, or log context and that operation itself fails.","commonSituations":"Task abort/cleanup hooks that fail because the underlying resource is already broken (network down, file handle invalid); catch blocks performing rollback that throw their own exceptions; nested failures during commit failure handling in snapshot producers.","solutions":["Inspect the logged suppressed exception to find why the catch block failed; the primary exception (also logged) is the root cause to fix first.","Make the catchBlock defensive: wrap its risky operations so it cannot throw, or check resource state before attempting cleanup.","Fix the underlying operation that caused the initial failure — once the primary failure stops occurring, the catch block won't run.","If the catch block calls close/abort on shared resources, ensure it handles 'already closed/broken' states gracefully."],"exampleFix":"// before\nExceptionUtil.runSafely(...).catchBlock(failure -> {\n  writer.abort(); // may throw if writer already broken\n});\n\n// after\nExceptionUtil.runSafely(...).catchBlock(failure -> {\n  try {\n    writer.abort();\n  } catch (Exception cleanupEx) {\n    LOG.warn(\"Abort during failure handling failed\", cleanupEx);\n  }\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Catch-block failures are suppressed onto the primary failure; always log and 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 (catch block): {}\", s.getMessage(), s);\n  }\n  throw e;\n}","preventionTips":["Keep catch blocks in runSafely simple and failure-proof (wrap risky cleanup internally).","Always log getSuppressed() when handling exceptions from ExceptionUtil.runSafely.","Fix root-cause failures first; catch-block errors are secondary symptoms.","Make abort/rollback hooks tolerate already-broken resources."],"tags":["exception-handling","suppressed-exception","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-14T16:17:12.679Z"}