{"record":{"id":"a10edf9c1ed5f157","repo":"apache/iceberg","slug":"failed-to-check-the-state-of-the-lock-s-a10edf","errorCode":null,"errorMessage":"Failed to check the state of the lock %s","messagePattern":"Failed to check the state of the lock (.+?)","errorType":"exception","errorClass":"UncheckedSQLException","httpStatus":null,"severity":"error","filePath":"flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java","lineNumber":230,"sourceCode":"    @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        //\n        // To prevent the situation above we fetch the current lockId, and remove the lock\n        // only with the given id.\n        String instanceId = instanceId();","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L212-L248","documentation":"Thrown by JdbcLock.isHeld when the SELECT that checks lock ownership fails with a SQLException. The lock state cannot be determined, so the caller gets an UncheckedSQLException wrapping the original SQL error. tryLock uses isHeld in its recovery path, so this can also surface during lock acquisition retries.","triggerScenarios":"The lock-state SELECT fails: connection dropped mid-query, lock table dropped or altered, wrong schema/table name, database timeout, or permissions on SELECT revoked.","commonSituations":"Database connection pool exhaustion under load; network blip between Flink taskmanager and the JDBC database; someone manually dropped or renamed the lock table; DB user permissions changed.","solutions":["Read the wrapped SQLException (getCause) for the exact SQL error and fix accordingly","Verify the lock table still exists and the configured user has SELECT on it","Check connection pool sizing and DB connectivity/network stability from the taskmanager","Retry the operation — transient connection errors often resolve on the next attempt"],"exampleFix":"// before: granting read-only access but revoking SELECT on lock tables\nREVOKE SELECT ON iceberg_lock FROM maintenance_user; // isHeld fails\n// after: keep SELECT on the lock tables for the maintenance user\nGRANT SELECT ON iceberg_lock TO maintenance_user;","handlingStrategy":"retry","validationCode":"// preflight: lock table exists and is readable\ntry (Connection c = ds.getConnection();\n     ResultSet rs = c.createStatement().executeQuery(\"SELECT 1 FROM iceberg_lock LIMIT 1\")) {\n  // OK\n} catch (SQLException e) { alert(\"Lock table check failed: \" + e.getMessage()); }","typeGuard":null,"tryCatchPattern":"try {\n  maintenanceResult = trigger.withLock(...);\n} catch (UncheckedSQLException e) {\n  if (isTransient(e)) { backoffAndRetry(); } else { throw e; }\n}","preventionTips":["Keep SELECT privileges on lock tables for the maintenance user across permission changes","Use connection pool validation (test-on-borrow) to prune dead connections","Monitor DB uptime; alert on lock table schema changes","Retry transient SQL states (e.g. connection errors) with backoff"],"tags":["jdbc","sql","locking","database-query","flink"],"backgroundTag":"database-query-failed","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"}