apache/iceberg · warning · UncheckedInterruptedException

Interrupted during isHeld

Error message

Interrupted during isHeld

What it means

JdbcLock.isHeld runs a SELECT through the connection pool to check the lock row's instance ID. If the thread is interrupted during that query, the interrupt flag is restored and UncheckedInterruptedException('Interrupted during isHeld') is thrown; SQLException instead becomes 'Failed to check the state of the lock'.

Source

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

    }

    @SuppressWarnings("checkstyle:NestedTryDepth")
    @Override
    public boolean isHeld() {
      try {
        return pool.run(
            conn -> {
              try (PreparedStatement sql = conn.prepareStatement(GET_LOCK_SQL)) {
                sql.setString(1, type.key);
                sql.setString(2, lockId);
                try (ResultSet rs = sql.executeQuery()) {
                  return rs.next();
                }
              }
            });
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        throw new UncheckedInterruptedException(e, "Interrupted during isHeld");
      } catch (SQLException e) {
        // SQL exception happened when getting lock information
        throw new UncheckedSQLException(e, "Failed to check the state of the lock %s", this);
      }
    }

    @SuppressWarnings("checkstyle:NestedTryDepth")
    @Override
    public void unlock() {
      try {
        // Possible concurrency issue:
        // - `unlock` and `tryLock` happens at the same time when there is an existing lock
        //
        // Steps:
        // 1. `unlock` removes the lock in the database, but there is a temporary connection failure
        // 2. `lock` finds that there is no lock, so creates a new lock
        // 3. `unlock` retries the lock removal and removes the new lock
        //

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. If part of intentional cancellation, ignore and shut down cleanly.
  2. If unexpected, find the interrupting component (cancel command, watchdog) and align shutdown ordering.
  3. Reduce lock-table query latency (indexes, DB load) so isHeld completes fast.
  4. Restart the trigger job to re-attempt lock acquisition.

Example fix

// no code fix; operational: ensure graceful shutdown stops the trigger loop before cancelling tasks
Defensive patterns

Strategy: try-catch

Validate before calling

// avoid calling isHeld on an interrupted thread
if (Thread.currentThread().isInterrupted()) {
    throw new IllegalStateException("Thread already interrupted");
}

Try / catch

try {
    held = lock.isHeld();
} catch (UncheckedInterruptedException e) {
    Thread.currentThread().interrupt();
    throw e; // propagate as cancellation
}

Prevention

When it happens

Trigger: isHeld (invoked during tryLock's failure-recovery path or by the trigger loop) interrupted mid-SELECT — job cancel/failover while querying the lock table.

Common situations: Cancellation during lock-state verification; slow SELECTs on a contended DB widening the interruption window.

Related errors


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