SonarSource/sonarqube · critical · java.lang.IllegalStateException
Failed to read content of table SCHEMA_MIGRATIONS
Error message
Failed to read content of table SCHEMA_MIGRATIONS
What it means
MigrationHistoryImpl.getLastMigrationNumber reads the SCHEMA_MIGRATIONS table to find the last applied migration version. An SQLException while querying it is wrapped in IllegalStateException "Failed to read content of table SCHEMA_MIGRATIONS". This means the migration framework cannot determine which migrations have already been applied.
Source
Thrown at server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryImpl.java:77
}
}
@Override
public void stop() {
// nothing to do
}
@Override
public Optional<Long> getLastMigrationNumber() {
try (Connection connection = database.getDataSource().getConnection()) {
List<Long> versions = selectVersions(connection);
if (!versions.isEmpty()) {
return Optional.of(versions.get(versions.size() - 1));
}
return Optional.empty();
} catch (SQLException e) {
throw new IllegalStateException("Failed to read content of table " + SCHEMA_MIGRATIONS_TABLE, e);
}
}
@Override
public void done(RegisteredMigrationStep dbMigration) {
long migrationNumber = dbMigration.getMigrationNumber();
try (Connection connection = database.getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("insert into schema_migrations(version) values (?)")) {
statement.setString(1, String.valueOf(migrationNumber));
statement.execute();
if (!connection.getAutoCommit()) {
connection.commit();
}
} catch (SQLException e) {
throw new IllegalStateException(String.format("Failed to insert row with value %s in table %s", migrationNumber, SCHEMA_MIGRATIONS_TABLE), e);
}
}View on GitHub (pinned to 184c821202)
Solutions
- Inspect the underlying SQLException cause to identify the exact failure (table missing, permission, lock, connection).
- Grant the sonar.jdbc.user SELECT (and generally DDL/DML) rights on the schema, or run migrations as the schema owner.
- If the table was manually removed or corrupted, restore it from backup or, for a fresh install, recreate the empty schema and let migrations run from scratch.
- Check for database locks/failed transactions from a previous interrupted migration and resolve them before restarting.
Example fix
// before — insufficient privileges GRANT CONNECT ON DATABASE sonar TO sonar_user; // after — grant schema rights so SCHEMA_MIGRATIONS is readable/writable GRANT ALL PRIVILEGES ON SCHEMA public TO sonar_user; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO sonar_user;
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-migration check
SELECT to_regclass('public.schema_migrations') IS NOT NULL AS table_exists;
SELECT has_table_privilege('sonar_user', 'schema_migrations', 'SELECT'); Try / catch
try {
history.getLastMigrationNumber();
} catch (IllegalStateException e) {
// inspect SQLException cause: grant rights, restore table, or rebuild schema
LOGGER.error("SCHEMA_MIGRATIONS unreadable; cause={}", e.getCause());
} Prevention
- Run migrations with the schema owner account that has full DDL/DML rights.
- Never manually drop or edit SCHEMA_MIGRATIONS; restore from backup instead.
- Take a DB snapshot before starting a major-version migration.
- Check for locks/failed transactions after any interrupted migration run.
When it happens
Trigger: The SELECT against SCHEMA_MIGRATIONS (called during start/migration bootstrap) throws SQLException — table missing or locked, permission denied, or a connection/SQL failure.
Common situations: User lacks SELECT rights on the table; the table was dropped or the schema was partially wiped manually; DB connection dropped mid-migration; an aborted earlier migration left the database locked or in a bad state.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- Failed to insert row with value %s in table %s
- Error during processing of row: [%s]
- Unknown dialect '%s'
- Unsupported dialect id
- Unknown dialect '%s'
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/b584256eeff5e791.
Report an issue: GitHub.