SonarSource/sonarqube · error · java.lang.IllegalStateException

Fail to execute %n (caught error, original was )

Error message

Fail to execute %s %n (caught %s error, original was %s)

What it means

DdlChange.execute wraps SQLExceptions from running a DDL statement in an IllegalStateException. When the SQL was auto-corrected or retried (e.g. Oracle ORA-01442 column-already-NOT-NULL handling strips NOT NULL and retries), the message includes the retry count and the original SQL, formatted as "Fail to execute <sql> (caught <n> error, original was <original>)".

Solutions

  1. Read the wrapped cause (the SQLException and its vendor code) to find the real database error.
  2. Inspect the printed original vs executed SQL to spot what the retry logic changed.
  3. Check DB user privileges and whether the migration is being re-run on a schema already migrated by a newer version.
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check for Oracle NOT NULL redundancy to avoid the retry path failing again
// SELECT NULLABLE FROM user_tab_columns WHERE table_name=? AND column_name=?  -> if 'Y', skip NOT NULL add

Try / catch

try {
  ddl.execute(context);
} catch (IllegalStateException e) {
  Throwable root = e.getCause();
  if (root instanceof SQLException se) {
    LOG.error("DDL failed (vendor code {}): {}", se.getErrorCode(), se.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: A DDL step's SQL throws a SQLException that the retry logic (errorCount > 0 or modified SQL) could not ultimately resolve — the second/final attempt also failed.

Common situations: Oracle migrations where a column is already NOT NULL and the retry with stripped NOT NULL still fails; syntax or permission errors on partially-migrated schemas; schema drift between environments.

Related errors


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

Appendix: source

Thrown at server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DdlChange.java:106

    private void execute(String original, String sql, int errorCount) {
      try (Statement stmt = writeConnection.createStatement()) {
        stmt.execute(sql);
        writeConnection.commit();
      } catch (SQLException e) {
        if (errorCount < ERROR_HANDLING_THRESHOLD) {
          String message = e.getMessage();
          if (message.contains("ORA-01451")) {
            String newSql = nullPattern.matcher(sql).replaceFirst("");
            execute(original, newSql, errorCount + 1);
            return;
          } else if (message.contains("ORA-01442")) {
            String newSql = notNullPattern.matcher(sql).replaceFirst("");
            execute(original, newSql, errorCount + 1);
            return;
          }
        }
        throw new IllegalStateException(messageForIseOf(original, sql, errorCount), e);
      } catch (Exception e) {
        throw new IllegalStateException(messageForIseOf(original, sql, errorCount), e);
      }
    }

    private static String messageForIseOf(String original, String sql, int errorCount) {
      if (!original.equals(sql) || errorCount > 0) {
        return format("Fail to execute %s %n (caught %s error, original was %s)", sql, errorCount, original);
      } else {
        return format("Fail to execute %s", sql);
      }
    }

    @Override
    public void execute(String... sqls) {
      execute(asList(sqls));
    }

View on GitHub (pinned to 184c821202)