{"record":{"id":"6ca3108692721143","repo":"apache/iceberg","slug":"failed-to-create-s-lock-6ca310","errorCode":null,"errorMessage":"Failed to create %s lock","messagePattern":"Failed to create (.+?) 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":206,"sourceCode":"                int count = sql.executeUpdate();\n                LOG.info(\n                    \"Created {} lock with instanceId {} with row count {}\",\n                    this,\n                    newInstanceId,\n                    count);\n                return count == 1;\n              }\n            });\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n        throw new UncheckedInterruptedException(e, \"Interrupted during tryLock\");\n      } catch (SQLException e) {\n        // SQL exception happened when creating the lock. Check if the lock creation was\n        // successful behind the scenes.\n        if (newInstanceId.equals(instanceId())) {\n          return true;\n        } else {\n          throw new UncheckedSQLException(e, \"Failed to create %s lock\", this);\n        }\n      }\n    }\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            });","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L188-L224","documentation":"Thrown by JdbcLock.tryLock when the INSERT that creates the lock row fails with a SQLException AND the subsequent instanceId() check shows another instance owns the lock (i.e. the lock was not successfully created behind the scenes). It wraps the original SQL error; the lock remains held by a different instance.","triggerScenarios":"tryLock's INSERT hits a constraint/violation or connection error, and the recovery check `newInstanceId.equals(instanceId())` returns false because another maintenance instance already inserted its lock row.","commonSituations":"Two Flink jobs or restarted taskmanagers both configured to run maintenance on the same table; duplicate lock rows from a previous crashed run with a different instance id; database failover mid-insert.","solutions":["Check who currently holds the lock (query the lock table's instance id / timestamp) and wait or clear stale locks","Ensure only one maintenance instance is configured per table — a second concurrent job will lose tryLock","If the holder is a crashed job, delete the stale lock row so tryLock can succeed","Inspect the wrapped SQLException (getCause) for the underlying constraint or connectivity issue"],"exampleFix":"// before: two jobs trigger maintenance on the same table concurrently\njob1: TableMaintenance...lockFactory(jdbcLockFactory).schedule()\njob2: TableMaintenance...lockFactory(jdbcLockFactory).schedule() // tryLock fails\n// after: single maintenance trigger, or remove stale lock row first\nDELETE FROM iceberg_lock WHERE installed_on < NOW() - INTERVAL '1 hour';","handlingStrategy":"retry","validationCode":"// before triggering maintenance, check no other instance holds the lock\nSELECT lock_id, instance_id, created_at FROM iceberg_lock WHERE lock_id = ?;\n// if instance_id differs and created_at is recent, another job owns it","typeGuard":null,"tryCatchPattern":"try {\n  lock.tryLock();\n} catch (UncheckedSQLException e) {\n  if (isStaleLock(e)) { deleteStaleLockRow(); retryLater(); }\n  else throw e;\n}","preventionTips":["Guarantee single-runner semantics: one Flink job triggers maintenance per table","Add a cleanup job that removes lock rows older than a safe threshold (crashed holders)","Use distinct lock ids per table so jobs do not fight over the same lock row","Inspect the cause chain — a constraint violation usually means someone else inserted first"],"tags":["jdbc","locking","sql","flink","lock-contention"],"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"}