{"record":{"id":"93d7fa1f9d284d30","repo":"apache/iceberg","slug":"interrupted-during-unlock","errorCode":null,"errorMessage":"Interrupted during unlock","messagePattern":"Interrupted during unlock","errorType":"exception","errorClass":"UncheckedInterruptedException","httpStatus":null,"severity":"error","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java","lineNumber":270,"sourceCode":"              conn -> {\n                try (PreparedStatement sql = conn.prepareStatement(DELETE_LOCK_SQL)) {\n                  sql.setString(1, type.key);\n                  sql.setString(2, lockId);\n                  sql.setString(3, instanceId);\n                  long count = sql.executeUpdate();\n                  LOG.info(\n                      \"Deleted {} lock with instanceId {} with row count {}\",\n                      this,\n                      instanceId,\n                      count);\n                }\n\n                return null;\n              });\n        }\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n        throw new UncheckedInterruptedException(e, \"Interrupted during unlock\");\n      } catch (SQLException e) {\n        // SQL exception happened when getting/updating lock information\n        throw new UncheckedSQLException(e, \"Failed to remove lock %s\", this);\n      }\n    }\n\n    @Override\n    public String toString() {\n      return MoreObjects.toStringHelper(this).add(\"type\", type).add(\"lockId\", lockId).toString();\n    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    private String instanceId() {\n      try {\n        return pool.run(\n            conn -> {\n              try (PreparedStatement sql = conn.prepareStatement(GET_LOCK_SQL)) {\n                sql.setString(1, type.key);","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L252-L288","documentation":"During JdbcLock.unlock(), the code blocks waiting on a Tasks-based DB operation to delete the lock row; an InterruptedException there is converted into UncheckedInterruptedException with this message after restoring the interrupt flag. It means the thread was interrupted while releasing the JDBC maintenance lock, and the lock release may not have completed.","triggerScenarios":"Task cancellation / Flink failover interrupts the thread executing unlock(); the interrupt fires while the SQL delete of the lock row is in flight.","commonSituations":"Job manager cancels the maintenance trigger task during a topology restart; operator kills the JVM (kill --thread interrupt); Flink restart strategy interrupts stuck unlock calls while the database is slow.","solutions":["Restore-and-propagate is already done by the library; let the thread finish its cancellation and rely on lock timeout/expiry for cleanup.","Re-run maintenance after the job restarts; the stale lock can be cleared via the JDBC table manually if needed.","Avoid interrupting maintenance threads; ensure slow DB calls have adequate timeouts instead of relying on interrupts.","Catch UncheckedInterruptedException at the scheduler boundary and log the lockId for manual cleanup.","Check the lock table for leftover rows after repeated interrupted unlocks and delete stale lockIds."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  lock.unlock();\n} catch (UncheckedInterruptedException e) {\n  Thread.currentThread().interrupt();\n  LOG.warn(\"Unlock interrupted, lockId {} may need cleanup\", lockId);\n}","preventionTips":["Do not cancel/interrupt threads mid-unlock; wait for release to finish","Use DB timeouts instead of thread interrupts for slow SQL","Schedule maintenance so it is not racing job restarts","Audit the lock table for stale rows after cancellations"],"tags":["flink","jdbc","lock","interrupt","maintenance"],"backgroundTag":"thread-interrupted","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"}