apache/iceberg · error · UncheckedSQLException
Failed to remove lock %s
Error message
Failed to remove lock %s
What it means
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.
Source
Thrown at flink/v1.20/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java:273
sql.setString(2, lockId);
sql.setString(3, instanceId);
long count = sql.executeUpdate();
LOG.info(
"Deleted {} lock with instanceId {} with row count {}",
this,
instanceId,
count);
}
return null;
});
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedInterruptedException(e, "Interrupted during unlock");
} catch (SQLException e) {
// SQL exception happened when getting/updating lock information
throw new UncheckedSQLException(e, "Failed to remove lock %s", this);
}
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this).add("type", type).add("lockId", lockId).toString();
}
@SuppressWarnings("checkstyle:NestedTryDepth")
private String instanceId() {
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()) {
if (rs.next()) {View on GitHub (pinned to 86d9c8fc54)
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.
Example fix
// before CREATE USER 'flink'@'%' IDENTIFIED BY '...'; -- no grants: unlock fails GRANT SELECT ON iceberg.* TO 'flink'@'%'; // after GRANT SELECT, DELETE, INSERT ON iceberg.* TO 'flink'@'%';
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-grant check
try (ResultSet rs = c.createStatement().executeQuery(
"SELECT DELETE_PRIV FROM mysql.db WHERE User='flink'")) { ... } Try / catch
try {
lock.unlock();
} catch (UncheckedSQLException e) {
LOG.error("Failed to remove lock {}", lockId, e.getCause());
// schedule manual cleanup / rely on lock expiry
} Prevention
- 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
When it happens
Trigger: SQLException while executing the DELETE/UPDATE on the lock table inside unlock(): connection lost, table missing, insufficient DELETE privilege, or DB deadlock/timeout.
Common situations: 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.
Related errors
- Failed to check the state of the lock %s
- Interrupted during unlock
- Failed to get lock information for %s
- Failed to check the state of the lock %s
- Failed to remove lock %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/239ef84130a39142.
Report an issue: GitHub.