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

  1. Inspect the wrapped SQLException cause for the root SQL error code and message.
  2. Grant the DB user CREATE/INSERT/SELECT privileges on the target schema.
  3. Create the lock tables manually with the expected schema (id/name columns per JdbcLockFactory) so runtime DDL is a no-op.
  4. 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

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


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;
    }

    @Override

View on GitHub (pinned to 86d9c8fc54)