SonarSource/sonarqube · critical · java.lang.IllegalStateException

Failed to create table schema_migrations

Error message

Failed to create table schema_migrations

What it means

Thrown by MigrationHistoryTableImpl.start() when creating the sonar-core-schema_migrations table fails with a SQLException. This table tracks which DB migrations have been applied; without it SonarQube cannot boot its database schema layer. The IllegalStateException wraps the underlying SQLException as the cause.

Solutions

  1. Check the root SQLException cause in logs for the actual JDBC error (access denied, unknown database, connection refused).
  2. Verify sonar.jdbc.url/username/password point to an existing, reachable database.
  3. Grant the database user CREATE TABLE privileges on the target schema.
  4. Test connectivity to the DB host/port and retry startup.

Example fix

// before
sonar.jdbc.url=jdbc:postgresql://localhost:5432/wrongdb
// after
sonar.jdbc.url=jdbc:postgresql://localhost:5432/sonar
Defensive patterns

Strategy: try-catch

Validate before calling

try (Connection c = DriverManager.getConnection(url, user, pass)) { DatabaseMetaData md = c.getMetaData(); } catch (SQLException e) { /* fail fast before migration */ }

Try / catch

try { historyTable.start(); } catch (IllegalStateException e) { logger.error("Migration history table creation failed; check DB connectivity/privileges", e.getCause()); throw e; }

Prevention

When it happens

Trigger: Calling start() when the database is unreachable, credentials are wrong, the configured user lacks CREATE TABLE privileges, or the schema/catalog does not exist.

Common situations: First startup against a fresh database with wrong JDBC settings; a DBA restricted the sonar user's DDL rights; network/firewall drops the JDBC connection; unsupported DB version or dialect.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/8205406562bb2e55. Report an issue: GitHub.

Appendix: source

Thrown at server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImpl.java:48

import org.sonar.server.platform.db.migration.sql.CreateTableBuilder;

public class MigrationHistoryTableImpl implements MigrationHistoryTable {
  private static final String VERSION_COLUMN_NAME = "version";

  private final Database database;

  public MigrationHistoryTableImpl(Database database) {
    this.database = database;
  }

  @Override
  public void start() {
    try (Connection connection = createDdlConnection(database)) {
      if (!DatabaseUtils.tableExists(NAME, connection)) {
        createTable(connection);
      }
    } catch (SQLException e) {
      throw new IllegalStateException("Failed to create table " + NAME, e);
    }
  }

  private void createTable(Connection connection) throws SQLException {
    List<String> sqls = new CreateTableBuilder(database.getDialect(), NAME)
      .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder().setColumnName(VERSION_COLUMN_NAME).setIsNullable(false).setLimit(255).build())
      .build();

    LoggerFactory.getLogger(MigrationHistoryTableImpl.class).info("Creating table " + NAME);
    for (String sql : sqls) {
      execute(connection, sql);
    }
  }

  private static Connection createDdlConnection(Database database) throws SQLException {
    Connection res = database.getDataSource().getConnection();
    res.setAutoCommit(false);
    return res;

View on GitHub (pinned to 184c821202)