{"record":{"id":"d9da1b75054d9301","repo":"apache/iceberg","slug":"unknown-throwable","errorCode":null,"errorMessage":"Unknown throwable","messagePattern":"Unknown throwable","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"warning","filePath":"api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java","lineNumber":117,"sourceCode":"      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);\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      }","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/api/src/main/java/org/apache/iceberg/util/ExceptionUtil.java#L99-L135","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["Unwrap the cause: e.getCause() holds the original throwable","Add the actual exception class as another runSafely type parameter so it is rethrown directly","Use the catchBlock callback to handle unexpected exception types before the fallback wraps them","Broaden the Block's declared exceptions (e.g. add E2) to cover the real failure type"],"exampleFix":"// before\nExceptionUtil.runSafely(block, null, null, IOException.class); // custom MyException gets wrapped\n// after\nExceptionUtil.runSafely(block, null, null, IOException.class, MyException.class);","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  ExceptionUtil.runSafely(block, catchBlock, finallyBlock, E1.class, E2.class, E3.class);\n} catch (RuntimeException e) {\n  if (\"Unknown throwable\".equals(e.getMessage()) && e.getCause() != null) {\n    handleOriginal(e.getCause());\n  } else {\n    throw e;\n  }\n}","preventionTips":["Declare every checked exception the block can throw in runSafely's type parameters","Use the catchBlock to absorb or classify unexpected exception types","Update runSafely parameters whenever a called library adds new checked exceptions","Always check getCause() on RuntimeExceptions from runSafely"],"tags":["java","exception-handling","wrapping","checked-exception"],"backgroundTag":"unexpected-response-shape","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"}