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
- 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.
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
- 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.
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
- Suppressing failure in finally block
- Suppressing exception in catch: {}
- The iceberg transaction has been committed, but we failed to
- Suppressing exception in catch: {}
- Suppressing exception in catch: {}
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/f1ef8d7ceaef591e.
Report an issue: GitHub.