apache/iceberg · warning

Suppressing failure in catch block

Error message

Suppressing failure in catch block

What it means

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.

Source

Thrown at api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java:108

      CatchBlock catchBlock,
      FinallyBlock finallyBlock,
      Class<? extends E1> e1Class,
      Class<? extends E2> e2Class,
      Class<? extends E3> e3Class)
      throws E1, E2, E3 {

    Throwable failure = null;
    try {
      return block.run();

    } catch (Throwable t) {
      failure = t;

      if (catchBlock != null) {
        try {
          catchBlock.run(failure);
        } catch (Exception e) {
          LOG.warn("Suppressing failure in catch block", e);
          failure.addSuppressed(e);
        }
      }

      tryThrowAs(failure, e1Class);
      tryThrowAs(failure, e2Class);
      tryThrowAs(failure, e3Class);
      tryThrowAs(failure, RuntimeException.class);
      throw new RuntimeException("Unknown throwable", failure);

    } finally {
      if (finallyBlock != null) {
        try {
          finallyBlock.run();
        } catch (Exception e) {
          if (failure != null) {
            LOG.warn("Suppressing failure in finally block", e);
            failure.addSuppressed(e);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Inspect the logged suppressed exception to find why the catch block failed; the primary exception (also logged) is the root cause to fix first.
  2. Make the catchBlock defensive: wrap its risky operations so it cannot throw, or check resource state before attempting cleanup.
  3. Fix the underlying operation that caused the initial failure — once the primary failure stops occurring, the catch block won't run.
  4. If the catch block calls close/abort on shared resources, ensure it handles 'already closed/broken' states gracefully.

Example fix

// before
ExceptionUtil.runSafely(...).catchBlock(failure -> {
  writer.abort(); // may throw if writer already broken
});

// after
ExceptionUtil.runSafely(...).catchBlock(failure -> {
  try {
    writer.abort();
  } catch (Exception cleanupEx) {
    LOG.warn("Abort during failure handling failed", cleanupEx);
  }
});
Defensive patterns

Strategy: try-catch

Try / catch

// Catch-block failures are suppressed onto the primary failure; always log and inspect suppressed exceptions.
try {
  operation.run();
} catch (Exception e) {
  LOG.error("Primary failure: {}", e.getMessage(), e);
  for (Throwable s : e.getSuppressed()) {
    LOG.error("Suppressed (catch block): {}", s.getMessage(), s);
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/f1ef8d7ceaef591e. Report an issue: GitHub.