{"record":{"id":"8d019b42821435ee","repo":"apache/iceberg","slug":"interrupted-in-sql-command","errorCode":null,"errorMessage":"Interrupted in SQL command","messagePattern":"Interrupted in SQL command","errorType":"exception","errorClass":"UncheckedInterruptedException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/jdbc/JdbcCatalog.java","lineNumber":782,"sourceCode":"  }\n\n  private int execute(Consumer<SQLException> sqlErrorHandler, String sql, String... args) {\n    try {\n      return connections.run(\n          conn -> {\n            try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) {\n              for (int pos = 0; pos < args.length; pos += 1) {\n                preparedStatement.setString(pos + 1, args[pos]);\n              }\n\n              return preparedStatement.executeUpdate();\n            }\n          });\n    } catch (SQLException e) {\n      sqlErrorHandler.accept(e);\n      throw new UncheckedSQLException(e, \"Failed to execute: %s\", sql);\n    } catch (InterruptedException e) {\n      throw new UncheckedInterruptedException(e, \"Interrupted in SQL command\");\n    }\n  }\n\n  @FunctionalInterface\n  interface RowProducer<R> {\n    R apply(ResultSet result) throws SQLException;\n  }\n\n  @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n  private <R> List<R> fetch(RowProducer<R> toRow, String sql, String... args) {\n    try {\n      return connections.run(\n          conn -> {\n            List<R> result = Lists.newArrayList();\n\n            try (PreparedStatement preparedStatement = conn.prepareStatement(sql)) {\n              for (int pos = 0; pos < args.length; pos += 1) {\n                preparedStatement.setString(pos + 1, args[pos]);","sourceCodeStart":764,"sourceCodeEnd":800,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/jdbc/JdbcCatalog.java#L764-L800","documentation":"execute() runs SQL through Tasks, which can be interrupted while waiting/retrying; on InterruptedException the catalog wraps it in UncheckedInterruptedException with \"Interrupted in SQL command\". The calling thread's interrupt flag was set while the catalog metadata write was in flight.","triggerScenarios":"Thread interrupt during a JdbcCatalog metadata write (e.g., task cancellation, executor shutdown, query timeout wrapper, Ctrl-C driven shutdown while committing catalog changes).","commonSituations":"Application shutdown cancelling in-flight commits; Spark/Flink task cancellation; custom timeouts that interrupt worker threads; blocking JDBC driver calls interrupted by watchdog threads.","solutions":["Avoid interrupting threads performing catalog commits; drain tasks before shutdown","Increase timeouts so watchdogs do not interrupt long SQL operations","Check whether the write completed despite interruption (verify catalog state) before retrying","Catch UncheckedInterruptedException, restore the interrupt flag, and unwind cleanly"],"exampleFix":"// before\ncatalog.createTable(ident, schema);\n// after\ntry {\n  catalog.createTable(ident, schema);\n} catch (UncheckedInterruptedException e) {\n  Thread.currentThread().interrupt();\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  catalog.dropTable(ident);\n} catch (UncheckedInterruptedException e) {\n  Thread.currentThread().interrupt();\n  // verify whether the write completed before retrying\n  throw e;\n}","preventionTips":["Do not interrupt threads that are committing catalog changes","Use graceful shutdown that awaits in-flight commits","Set generous timeouts so watchdogs never interrupt SQL writes","After interruption, verify catalog state before re-issuing the operation"],"tags":["jdbc","interrupt","concurrency"],"backgroundTag":"request-timeout","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"}