{"record":{"id":"aad90328086e1aeb","repo":"apache/iceberg","slug":"interrupted-during-isheld-aad903","errorCode":null,"errorMessage":"Interrupted during isHeld","messagePattern":"Interrupted during isHeld","errorType":"exception","errorClass":"UncheckedInterruptedException","httpStatus":null,"severity":"info","filePath":"flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java","lineNumber":227,"sourceCode":"    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    @Override\n    public boolean isHeld() {\n      try {\n        return pool.run(\n            conn -> {\n              try (PreparedStatement sql = conn.prepareStatement(GET_LOCK_SQL)) {\n                sql.setString(1, type.key);\n                sql.setString(2, lockId);\n                try (ResultSet rs = sql.executeQuery()) {\n                  return rs.next();\n                }\n              }\n            });\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n        throw new UncheckedInterruptedException(e, \"Interrupted during isHeld\");\n      } catch (SQLException e) {\n        // SQL exception happened when getting lock information\n        throw new UncheckedSQLException(e, \"Failed to check the state of the lock %s\", this);\n      }\n    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    @Override\n    public void unlock() {\n      try {\n        // Possible concurrency issue:\n        // - `unlock` and `tryLock` happens at the same time when there is an existing lock\n        //\n        // Steps:\n        // 1. `unlock` removes the lock in the database, but there is a temporary connection failure\n        // 2. `lock` finds that there is no lock, so creates a new lock\n        // 3. `unlock` retries the lock removal and removes the new lock\n        //","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L209-L245","documentation":"Thrown by JdbcLock.isHeld when the thread is interrupted while querying the lock table to determine whether the lock is still held. The interrupt flag is restored and the InterruptedException is wrapped in UncheckedInterruptedException. No lock state was determined.","triggerScenarios":"isHeld's SELECT against the lock table is interrupted — typically Flink task cancellation or executor shutdown while isHeld runs inside the tryLock recovery path.","commonSituations":"Job cancel/failover while the lock state check runs; slow database making the check window long enough to catch an interrupt; shutdown of the maintenance scheduler thread pool.","solutions":["Expected during cancellation — confirm the shutdown was intentional","If unexpected, trace the interrupt source (Flink cancel, executor shutdownNow) and fix lifecycle handling","Speed up the database (indexes on lock table keys) so isHeld completes quickly","Respect the restored interrupt flag; do not retry in a loop while interrupted"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  lock.isHeld();\n} catch (UncheckedInterruptedException e) {\n  Thread.currentThread().interrupt();\n  // treat as unknown lock state; abort current maintenance cycle\n}","preventionTips":["Index the lock table's primary key/lock_id so isHeld queries stay fast","Avoid interrupting threads during lock state checks","Keep the lock database close to the taskmanagers to minimize query latency"],"tags":["interrupted","locking","jdbc","flink","threading"],"backgroundTag":"operation-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"}