apache/iceberg · error · UncheckedInterruptedException

Interrupted during unlock

Error message

Interrupted during unlock

What it means

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.

Source

Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java:270

              conn -> {
                try (PreparedStatement sql = conn.prepareStatement(DELETE_LOCK_SQL)) {
                  sql.setString(1, type.key);
                  sql.setString(2, lockId);
                  sql.setString(3, instanceId);
                  long count = sql.executeUpdate();
                  LOG.info(
                      "Deleted {} lock with instanceId {} with row count {}",
                      this,
                      instanceId,
                      count);
                }

                return null;
              });
        }
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new UncheckedInterruptedException(e, "Interrupted during unlock");
      } catch (SQLException e) {
        // SQL exception happened when getting/updating lock information
        throw new UncheckedSQLException(e, "Failed to remove lock %s", this);
      }
    }

    @Override
    public String toString() {
      return MoreObjects.toStringHelper(this).add("type", type).add("lockId", lockId).toString();
    }

    @SuppressWarnings("checkstyle:NestedTryDepth")
    private String instanceId() {
      try {
        return pool.run(
            conn -> {
              try (PreparedStatement sql = conn.prepareStatement(GET_LOCK_SQL)) {
                sql.setString(1, type.key);

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Restore-and-propagate is already done by the library; let the thread finish its cancellation and rely on lock timeout/expiry for cleanup.
  2. Re-run maintenance after the job restarts; the stale lock can be cleared via the JDBC table manually if needed.
  3. Avoid interrupting maintenance threads; ensure slow DB calls have adequate timeouts instead of relying on interrupts.
  4. Catch UncheckedInterruptedException at the scheduler boundary and log the lockId for manual cleanup.
  5. Check the lock table for leftover rows after repeated interrupted unlocks and delete stale lockIds.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  lock.unlock();
} catch (UncheckedInterruptedException e) {
  Thread.currentThread().interrupt();
  LOG.warn("Unlock interrupted, lockId {} may need cleanup", lockId);
}

Prevention

When it happens

Trigger: Task cancellation / Flink failover interrupts the thread executing unlock(); the interrupt fires while the SQL delete of the lock row is in flight.

Common situations: 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.

Related errors


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