apache/iceberg · error · UncheckedInterruptedException
Interrupted during isHeld
Error message
Interrupted during isHeld
What it means
JdbcLockFactory's JdbcLock.isHeld() queries the JDBC catalog's lock table to determine whether this trigger holds its lock. If the thread waiting on the JDBC query is interrupted, the interruption is re-asserted and an UncheckedInterruptedException wrapping the original InterruptedException is thrown. This converts the checked interruption into a runtime exception so lock-state checks can fail fast in maintenance trigger threads.
Source
Thrown at flink/v2.2/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
- Check why the thread was interrupted (job cancellation, timeout watchdog) and ensure maintenance tasks run in a thread allowed to complete.
- Verify the JDBC database and network are responsive; slow queries increase the window for interruption.
- Adjust connection/validation timeouts (e.g., connection pool settings) so queries fail with SQLException instead of hanging until interrupted.
- Propagate and honor the interruption: since the flag is re-set via Thread.currentThread().interrupt(), let shutdown logic observe it and stop gracefully.
Example fix
// before
boolean held = lock.tryLock(); // may throw UncheckedInterruptedException
// after
try {
boolean held = lock.tryLock();
} catch (UncheckedInterruptedException e) {
Thread.currentThread().interrupt(); // restore flag, abort maintenance gracefully
return;
} Defensive patterns
Strategy: try-catch
Validate before calling
if (Thread.currentThread().isInterrupted()) { /* skip maintenance attempt */ } Try / catch
try { boolean held = lock.tryLock(); } catch (UncheckedInterruptedException e) { Thread.currentThread().interrupt(); return; } Prevention
- Avoid interrupting threads during maintenance commits; use graceful shutdown with drain time.
- Keep JDBC queries fast (timeouts, pool validation) so threads block only briefly.
- Check Thread.currentThread().isInterrupted() before starting lock operations.
- Log the interruption cause to distinguish cancellation from bugs.
When it happens
Trigger: Calling tryLock (which calls isHeld) on a JdbcLock when the executing thread is interrupted while blocked on the JDBC query (Tasks.foreach lambda doing rs.next() against the lock table).
Common situations: Flink job shutdown/cancel interrupting the maintenance trigger thread mid-query; JDBC driver stuck on a slow or unresponsive database so the thread sits blocked until interrupted; operator restarts cancelling the thread that acquires locks.
Related errors
- Interrupted during tryLock
- Interrupted during isHeld
- Interrupted during unlock
- Interrupted in call to initialize
- Failed to create %s lock
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/503e71bab57a5bb1.
Report an issue: GitHub.