{"record":{"id":"239ef84130a39142","repo":"apache/iceberg","slug":"failed-to-remove-lock-s","errorCode":null,"errorMessage":"Failed to remove lock %s","messagePattern":"Failed to remove lock (.+?)","errorType":"exception","errorClass":"UncheckedSQLException","httpStatus":null,"severity":"error","filePath":"flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java","lineNumber":273,"sourceCode":"                  sql.setString(2, lockId);\n                  sql.setString(3, instanceId);\n                  long count = sql.executeUpdate();\n                  LOG.info(\n                      \"Deleted {} lock with instanceId {} with row count {}\",\n                      this,\n                      instanceId,\n                      count);\n                }\n\n                return null;\n              });\n        }\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n        throw new UncheckedInterruptedException(e, \"Interrupted during unlock\");\n      } catch (SQLException e) {\n        // SQL exception happened when getting/updating lock information\n        throw new UncheckedSQLException(e, \"Failed to remove lock %s\", this);\n      }\n    }\n\n    @Override\n    public String toString() {\n      return MoreObjects.toStringHelper(this).add(\"type\", type).add(\"lockId\", lockId).toString();\n    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    private String instanceId() {\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                  if (rs.next()) {","sourceCodeStart":255,"sourceCodeEnd":291,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L255-L291","documentation":"JdbcLock.unlock() failed to delete/update the lock row in the JDBC lock table; the SQLException is wrapped into UncheckedSQLException with this message. The lock may still be held in the database even though unlock() threw.","triggerScenarios":"SQLException while executing the DELETE/UPDATE on the lock table inside unlock(): connection lost, table missing, insufficient DELETE privilege, or DB deadlock/timeout.","commonSituations":"DB user lacks DELETE privilege on the lock table; database failover drops the connection mid-unlock; lock table schema was altered; lock row already removed by another instance and the statement errors.","solutions":["Grant the JDBC user DELETE (and SELECT) privileges on the lock table.","Verify the lock table exists with the expected schema (create it via the JdbcCatalog init SQL).","Check the wrapped cause for SQLState to distinguish connectivity vs permission vs deadlock.","Manually remove the stale lock row from the lock table if the lock is blocking new maintenance.","Add DB-side retry/connection pool settings (e.g. socketTimeout) to survive transient failovers."],"exampleFix":"// before\nCREATE USER 'flink'@'%' IDENTIFIED BY '...'; -- no grants: unlock fails\nGRANT SELECT ON iceberg.* TO 'flink'@'%';\n// after\nGRANT SELECT, DELETE, INSERT ON iceberg.* TO 'flink'@'%';","handlingStrategy":"try-catch","validationCode":"// pre-grant check\ntry (ResultSet rs = c.createStatement().executeQuery(\n    \"SELECT DELETE_PRIV FROM mysql.db WHERE User='flink'\")) { ... }","typeGuard":null,"tryCatchPattern":"try {\n  lock.unlock();\n} catch (UncheckedSQLException e) {\n  LOG.error(\"Failed to remove lock {}\", lockId, e.getCause());\n  // schedule manual cleanup / rely on lock expiry\n}","preventionTips":["Grant DELETE privilege on the lock table","Keep lock-table schema stable across deployments","Handle DB failovers with connection retry settings","Clean stale lock rows from aborted jobs"],"tags":["flink","jdbc","lock","sql","maintenance"],"backgroundTag":"database-write-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"}