apache/iceberg · error · UncheckedSQLException
Failed to remove lock %s
Error message
Failed to remove lock %s
What it means
Thrown by JdbcLock.unlock when the SQL statements that read/update lock info and delete the lock row fail with a SQLException. The lock could not be released, leaving it possibly held (stale). The original SQL error is wrapped in UncheckedSQLException.
Source
Thrown at flink/v2.1/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
- Inspect the wrapped SQLException (getCause) for the exact SQL failure
- Grant the maintenance DB user UPDATE/DELETE privileges on the lock table
- Check for orphaned/stale lock rows after failure and delete them before the next run
- Verify DB connectivity and retry the release; enable connection pool validation to drop dead connections
Example fix
// before GRANT SELECT, INSERT ON iceberg_lock TO maintenance_user; // unlock DELETE fails // after GRANT SELECT, INSERT, UPDATE, DELETE ON iceberg_lock TO maintenance_user;
Defensive patterns
Strategy: retry
Validate before calling
// verify DML rights before running maintenance
try (Connection c = ds.getConnection()) {
c.setAutoCommit(false);
try (Statement s = c.createStatement()) {
s.execute("DELETE FROM iceberg_lock WHERE lock_id = '__probe__'");
}
c.rollback();
} catch (SQLException e) { throw new IllegalStateException("No DELETE grant on lock table"); } Try / catch
try {
lock.unlock();
} catch (UncheckedSQLException e) {
log.error("Lock release failed; manual stale-lock cleanup required", e);
scheduleStaleLockCleanup();
} Prevention
- Grant UPDATE and DELETE on the lock table to the maintenance user, not just SELECT/INSERT
- Detect and delete orphaned lock rows from crashed jobs on a schedule
- Check the cause chain for deadlock/timeout SQL states and retry those
- Avoid DB failovers during maintenance windows; prefer a highly available lock DB endpoint
When it happens
Trigger: unlock's SELECT/UPDATE/DELETE against the lock table fails: lost connection, lock table missing, insufficient DELETE privilege, or a deadlock/timeout on the lock row.
Common situations: DB failover during unlock; maintenance user granted only SELECT/INSERT but not DELETE; network partition; long-running transaction holding the lock row causes timeout.
Related errors
- Failed to create %s lock
- Failed to check the state of the lock %s
- Interrupted during unlock
- Failed to get lock information for %s
- Failed to remove lock %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/063340f97da9ade4.
Report an issue: GitHub.