apache/iceberg · warning · RuntimeException

Unknown throwable

Error message

Unknown throwable

What it means

ExceptionUtil.runSafely's fallback: when the block fails with a Throwable that is not an instance of any of the three declared exception classes nor a RuntimeException, it is wrapped in RuntimeException("Unknown throwable"). This happens with checked exceptions outside the declared set (Errors are re-thrown by tryThrowAs only if matching; arbitrary Throwables land here).

Source

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

      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);
          } else {
            tryThrowAs(e, e1Class);
            tryThrowAs(e, e2Class);
            tryThrowAs(e, e3Class);
            tryThrowAs(e, RuntimeException.class);
            throw new RuntimeException("Unknown exception in finally block", e);
          }
        }
      }

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Unwrap the cause: e.getCause() holds the original throwable
  2. Add the actual exception class as another runSafely type parameter so it is rethrown directly
  3. Use the catchBlock callback to handle unexpected exception types before the fallback wraps them
  4. Broaden the Block's declared exceptions (e.g. add E2) to cover the real failure type

Example fix

// before
ExceptionUtil.runSafely(block, null, null, IOException.class); // custom MyException gets wrapped
// after
ExceptionUtil.runSafely(block, null, null, IOException.class, MyException.class);
Defensive patterns

Strategy: try-catch

Try / catch

try {
  ExceptionUtil.runSafely(block, catchBlock, finallyBlock, E1.class, E2.class, E3.class);
} catch (RuntimeException e) {
  if ("Unknown throwable".equals(e.getMessage()) && e.getCause() != null) {
    handleOriginal(e.getCause());
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: The Block throws a checked exception type not among e1Class/e2Class/e3Class (e.g. a Block declaring IOException but throwing a custom checked exception), and no catchBlock absorbs it.

Common situations: Refactoring that adds a new exception type to a lambda without updating runSafely's declared exception classes; library upgrades introducing new checked exceptions from called code.

Related errors


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