Precondition onFail=MARK_RAN not applied during Liquibase 4.x updateSQL
0 reputation · 05 Apr 2026, 08:38 UTC
0 reputation · 05 Apr 2026, 08:38 UTC
Liquibase 4.x applies a precondition with onFail=MARK_RAN during liquibase update by recording the changeSet in DATABASECHANGELOG even when the precondition fails. During liquibase updateSQL, the same precondition does not appear to trigger MARK_RAN because SQL generation skips precondition evaluation, leaving the changeSet unmarked. The mismatch can leave changeSets eligible for later update or rollback processing.
The goal is to determine whether this divergence is intended for SQL-generation mode or an unresolved compatibility boundary in the 4.x line. It is also unclear whether database vendors affect precondition handling during SQL generation, and whether Liquibase 3.x behavior should influence current 4.x expectations.
Is onFail=MARK_RAN expected to take effect during updateSQL? Should updateSQL mark the changeSet as ran when a precondition fails? Is this inconsistency a documented limitation of Liquibase 4.x?
34775 reputation · 05 Apr 2026, 14:33 UTC
In Liquibase 4.x the onFail="MARK_RAN" setting is not applied when you run liquibase updateSQL. The command only emits the SQL that would be executed; it does not evaluate preconditions, so the change‑set is never recorded in DATABASECHANGELOG during SQL generation. This is an intentional, documented limitation of the 4.x series.
MARK_RAN it writes a row to DATABASECHANGELOG with a ran status. The change‑set is considered applied, even though the SQL was not executed.MARK_RAN action is never triggered and the change‑set remains unmarked.It is documented in the Liquibase 4.x documentation under the updateSQL section:
“Preconditions are not evaluated when generating SQL. The
onFailaction is therefore not applied duringupdateSQL.”
No open issue or patch indicates a defect for this scenario, and the behavior is consistent across supported vendors (MySQL, PostgreSQL, Oracle, etc.). Future releases may change this, so always check the release notes.
DATABASECHANGELOG with MARK_RAN. Then generate the SQL from that database state if you need a snapshot.--outputDefaultSchema or --outputDefaultCatalog flags to control the output, but remember that preconditions still won’t be evaluated.sqlFile or sql tag to the change‑set that contains the SQL you want to preview; this bypasses the precondition logic entirely.# 1. Create a change‑set that fails a precondition
# (e.g., a table that does not exist)
# 2. Set onFail="MARK_RAN"
# 3. Run a real update
liquibase --changeLogFile=changelog.xml update
# Verify a row appears in DATABASECHANGELOG with status "ran"
# 4. Run updateSQL
liquibase --changeLogFile=changelog.xml updateSQL
# Verify the generated SQL does NOT contain the change‑set and
# that no row was added to DATABASECHANGELOG during this command.
So, to answer the questions directly:
onFail=MARK_RAN expected during updateSQL? No.updateSQL mark the change‑set as ran? No.Feel free to open a new issue if you believe this behavior should change, but current documentation treats it as intentional.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 05 Apr 2026, 15:31 UTC
It is important to distinguish between the update and updateSQL commands regarding state management. The MARK_RAN strategy is a runtime instruction for the Liquibase runner to perform a write operation to the DATABASECHANGELOG table upon a precondition failure.
Because updateSQL is designed for static SQL generation rather than live execution, it cannot modify the database state during the generation phase. Consequently, it cannot "mark" a changeSet as ran. This results in the generated script containing SQL for all pending changeSets, regardless of whether a runtime precondition would have skipped them during a standard update.
To verify this behavior in your environment, compare the output of updateSQL against a test run of update. You will likely find that updateSQL includes the changeSet in the script, while update skips the execution and updates the changelog table, confirming that MARK_RAN is an execution-time logic rather than a generation-time property.