apache/iceberg · error · UncheckedSQLException
Cannot initialize JDBC table maintenance lock
Error message
Cannot initialize JDBC table maintenance lock
What it means
Catch-all handler in JdbcLockFactory.initializeLockTables: any SQLException not classified as a timeout or connection failure during lock-table initialization is wrapped in UncheckedSQLException with this generic message. Inspect the cause for the actual SQL error (e.g. syntax, permissions, table already exists in an incompatible state).
Solutions
- Inspect the wrapped SQLException cause for the root SQL error code and message.
- Grant the DB user CREATE/INSERT/SELECT privileges on the target schema.
- Create the lock tables manually with the expected schema (id/name columns per JdbcLockFactory) so runtime DDL is a no-op.
- Verify the JDBC URL points to the intended database/schema.
Example fix
// before (no privileges) GRANT CONNECT ON DATABASE app TO flink_user; // after GRANT CONNECT, CREATE ON DATABASE app TO flink_user;
Defensive patterns
Strategy: validation
Validate before calling
// verify privileges and table existence up front
SELECT has_database_privilege(current_user, 'app', 'CREATE');
SELECT to_regclass('public.iceberg_lock'); -- null means tables will be created Try / catch
try {
lockFactory.open();
} catch (UncheckedSQLException e) {
SQLException sql = (SQLException) e.getCause();
// log sql.getSQLState() and sql.getErrorCode() to identify the real cause
throw e;
} Prevention
- Grant CREATE privileges to the lock-factory DB user
- Create lock tables manually via migration scripts
- Always log the wrapped cause's SQLState/ErrorCode
- Confirm the JDBC URL schema/database exists
When it happens
Trigger: JdbcLockFactory.create/open -> initializeLockTables when executing the lock-table DDL/query throws any other SQLException (permission denied, syntax error, catalog missing, etc.).
Common situations: DB user lacking CREATE TABLE privileges, unsupported SQL dialect, schema/database not existing, or a partially created lock table from a failed earlier run.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- Cannot initialize JDBC table maintenance lock: Connection…
- Cannot initialize JDBC table maintenance lock: Query timed…
- Failed to check the state of the lock
- Failed to create lock
- Failed to get lock information for
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/a8c69687ac7eb320.
Report an issue: GitHub.
Appendix: source
Thrown at flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java:155
LOG.debug("Flink maintenance lock table already exists");
return true;
}
}
LOG.info("Creating Flink maintenance lock table {}", LOCK_TABLE_NAME);
try (PreparedStatement ps = conn.prepareStatement(CREATE_LOCK_TABLE_SQL)) {
ps.execute();
}
return true;
});
} catch (SQLTimeoutException e) {
throw new UncheckedSQLException(
e, "Cannot initialize JDBC table maintenance lock: Query timed out");
} catch (SQLTransientConnectionException | SQLNonTransientConnectionException e) {
throw new UncheckedSQLException(
e, "Cannot initialize JDBC table maintenance lock: Connection failed");
} catch (SQLException e) {
throw new UncheckedSQLException(e, "Cannot initialize JDBC table maintenance lock");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new UncheckedInterruptedException(e, "Interrupted in call to initialize");
}
}
private static class JdbcLock implements TriggerLockFactory.Lock {
private final JdbcClientPool pool;
private final String lockId;
private final Type type;
private JdbcLock(JdbcClientPool pool, String lockId, Type type) {
this.pool = pool;
this.lockId = lockId;
this.type = type;
}
@OverrideView on GitHub (pinned to 86d9c8fc54)