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
- Read the failing SQL statement in the message and the chained SQLException to identify the concrete database error.
- Restore from a backup (or drop/recreate the schema) and run the schema operation once against a clean state.
- Grant the DB user the required DDL privileges (CREATE TABLE, ALTER, DROP, INDEX).
- 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
- Read the failing SQL statement embedded in the message to identify the exact problem
- Use databaseSchemaUpdate=true (idempotent) instead of re-running 'create'
- Grant the DB user sufficient DDL privileges
- Verify databaseType/databaseVendor detection matches the actual database
- Back up before upgrades; restore to clean state after failed partial schema runs
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
- couldn't get ${context} db schema version
- Failed to get change log version from ${changeLogTableName}
- Could not update Flowable database schema: unknown version f
- SQL Exception when getting value. Message: ${e.getMessage()}
- Could not set database schema on connection
AI-assisted analysis of flowable/flowable-engine@d6d39ce1c6 (2026-09-11).
Data as JSON: /api/errors/cfc6fcb8e0528155.
Report an issue: GitHub.