flowable/flowable-engine · critical · FlowableException

couldn't ${operation} db schema: ${exceptionSqlStatement}

Error message

couldn't ${operation} db schema: ${exceptionSqlStatement}

What it means

executeSchemaResource's outer catch wraps any exception raised while executing a schema SQL statement into FlowableException('couldn't <operation> db schema: <failing statement>'). The message includes the exact SQL statement that failed, so the error names both the operation (create/upgrade/drop) and the offending DDL/DML.

Source

Thrown at modules/flowable-engine-common/src/main/java/org/flowable/common/engine/impl/db/AbstractSqlScriptBasedDbSchemaManager.java:348

                            sqlStatement = null;
                        }
                        
                    } else {
                        sqlStatement = addSqlStatementPiece(sqlStatement, line);
                    }
                }

                line = readNextTrimmedLine(reader);
            }

            if (exception != null) {
                throw exception;
            }

            logger.debug("flowable db schema {} for component {} successful", operation, component);

        } catch (Exception e) {
            throw new FlowableException("couldn't " + operation + " db schema: " + exceptionSqlStatement, e);
        }
    }

    /**
     * MySQL is funny when it comes to timestamps and dates.
     * 
     * More specifically, for a DDL statement like 'MYCOLUMN timestamp(3)': - MySQL 5.6.4+ has support for timestamps/dates with millisecond (or smaller) precision. The DDL above works and the data in
     * the table will have millisecond precision - MySQL before 5.5.3 allows the DDL statement, but ignores it. The DDL above works but the data won't have millisecond precision - 
     * MySQL 5.5.3 before [version] after 5.6.4 gives and exception when using the DDL above.
     * 
     * Also, the 5.5 and 5.6 branches of MySQL are both actively developed and patched.
     * 
     * Hence, when doing auto-upgrade/creation of the Flowable tables, the default MySQL DDL file is used and all timestamps/datetimes are converted to not use the millisecond precision by string
     * replacement done in the method below.
     * 
     * If using the DDL files directly (which is a sane choice in production env.), there is a distinction between MySQL version before 5.6.
     */
    protected String updateDdlForMySqlVersionLowerThan56(String ddlStatements) {

View on GitHub (pinned to d6d39ce1c6)

Solutions

  1. Read the failing SQL statement in the message and the chained SQLException to identify the concrete database error.
  2. Restore from a backup (or drop/recreate the schema) and run the schema operation once against a clean state.
  3. Grant the DB user the required DDL privileges (CREATE TABLE, ALTER, DROP, INDEX).
  4. Verify databaseType detection matches the actual database so the correct vendor scripts are used.

Example fix

// before: rerunning create on a half-created schema
engineConfig.setDatabaseSchemaUpdate("create");
// after
engineConfig.setDatabaseSchemaUpdate("true"); // checks what exists and upgrades/creates only what is missing
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: run schema scripts on a scratch database copy to catch failing DDL early
boolean ok = scratchDb.apply(flowableSchemaScripts);

Try / catch

try { engineCfg.buildProcessEngine(); } catch (FlowableException e) { if (e.getMessage().startsWith("couldn't ")) { log.error("Failed schema op, failing statement: {} cause: {}", e.getMessage(), e.getCause(), e.getCause()); } throw e; }

Prevention

When it happens

Trigger: Any SQL statement in a schema create/upgrade/drop script failing — object already exists, insufficient privileges, syntax unsupported by the database, table in use — during dbSchemaCreate, dbSchemaUpgrade, or dbSchemaDrop.

Common situations: Re-running schema creation on a partially populated database; DB user lacking CREATE/ALTER privileges; database type auto-detection mismatching the actual DB (Oracle script run on PostgreSQL); rerunning an interrupted upgrade that already applied some statements.

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


AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11). Data as JSON: /api/errors/cfc6fcb8e0528155. Report an issue: GitHub.