{"record":{"id":"2f68d401c27de522","repo":"apache/iceberg","slug":"cannot-initialize-jdbc-table-maintenance-lock-2f68d4","errorCode":null,"errorMessage":"Cannot initialize JDBC table maintenance lock","messagePattern":"Cannot initialize JDBC table maintenance 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":155,"sourceCode":"                LOG.debug(\"Flink maintenance lock table already exists\");\n                return true;\n              }\n            }\n            LOG.info(\"Creating Flink maintenance lock table {}\", LOCK_TABLE_NAME);\n            try (PreparedStatement ps = conn.prepareStatement(CREATE_LOCK_TABLE_SQL)) {\n              ps.execute();\n            }\n\n            return true;\n          });\n    } catch (SQLTimeoutException e) {\n      throw new UncheckedSQLException(\n          e, \"Cannot initialize JDBC table maintenance lock: Query timed out\");\n    } catch (SQLTransientConnectionException | SQLNonTransientConnectionException e) {\n      throw new UncheckedSQLException(\n          e, \"Cannot initialize JDBC table maintenance lock: Connection failed\");\n    } catch (SQLException e) {\n      throw new UncheckedSQLException(e, \"Cannot initialize JDBC table maintenance lock\");\n    } catch (InterruptedException e) {\n      Thread.currentThread().interrupt();\n      throw new UncheckedInterruptedException(e, \"Interrupted in call to initialize\");\n    }\n  }\n\n  private static class JdbcLock implements TriggerLockFactory.Lock {\n    private final JdbcClientPool pool;\n    private final String lockId;\n    private final Type type;\n\n    private JdbcLock(JdbcClientPool pool, String lockId, Type type) {\n      this.pool = pool;\n      this.lockId = lockId;\n      this.type = type;\n    }\n\n    @Override","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.1/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L137-L173","documentation":"Thrown by JdbcLockFactory.initializeLockTables (called from open) when the DDL statements that create the maintenance lock tables fail with a generic SQLException. The lock-table initialization (CREATE TABLE for the trigger lock tables) could not be completed against the configured JDBC database. This is the catch-all branch after timeout and connection-failure cases have been handled separately.","triggerScenarios":"Calling JdbcLockFactory.create/open where the CREATE TABLE for the lock tables fails: the configured user lacks CREATE privileges, the lock table name collides with an existing incompatible table, the database/schema does not exist, or the JDBC URL points to a non-existent database.","commonSituations":"Misconfigured lock-table JdbcCatalog URI in the maintenance TableMaintenance builder; deploying to an environment where the DB user is read-only; switching databases (e.g. from Postgres to MySQL) without pre-creating the schema; a partially-created lock table left over from a failed prior run.","solutions":["Verify the JDBC URI in the JdbcLockFactory configuration points to an existing database and the driver is on the classpath","Grant the configured DB user CREATE TABLE privileges in the target schema, or pre-create the lock tables manually","Check the underlying SQLException (getCause) for the exact SQL error code and fix the table definition or name conflict","Drop leftover/corrupt lock tables from a previous failed initialization and retry"],"exampleFix":"// before\nTableMaintenance.forTable(table)\n    .lockFactory(JdbcLockFactory.builder()\n        .jdbcUrl(\"jdbc:postgresql://db:5432/missing_db\")\n        ...) // fails: database missing_db does not exist\n// after\nTableMaintenance.forTable(table)\n    .lockFactory(JdbcLockFactory.builder()\n        .jdbcUrl(\"jdbc:postgresql://db:5432/iceberg\")\n        ...) // database exists, user has CREATE privilege","handlingStrategy":"validation","validationCode":"// before configuring JdbcLockFactory, verify DB access\ntry (Connection c = DriverManager.getConnection(jdbcUrl, user, pass)) {\n  DatabaseMetaData md = c.getMetaData();\n  boolean canCreate = !c.getMetaData().getTables(null, null, lockTableName + \"%\", new String[]{\"TABLE\"}).next()\n      || c.createStatement().executeQuery(\"SELECT 1\").next(); // connection ok\n} catch (SQLException e) { throw new IllegalStateException(\"Lock DB unreachable: \" + e.getMessage()); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pre-create the lock tables with a privileged account and give the runtime user only DML rights","Validate the JDBC URI and driver availability in deployment config tests","Use a dedicated database/schema for maintenance locks to avoid name collisions","Smoke-test lock factory creation in CI against the same DB engine as production"],"tags":["jdbc","sql","flink","lock-initialization","database"],"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"}