Liquibase Preconditions Fails

Preconditions are used to check if the database has all the requirements met for the ChangeSet to run to avoid any future errors. If Preconditions passes, Liquibase will execute the ChangeSet successfully, but if Preconditions fails and the Database doesn't meet all necessary requirements, Liquibase allows modification of the execution behaviors.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions>
			<rowCount expectedRows="5" tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Gala" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

The above Preconditions is checking that the apple table should have at least 5 rows, but it results in an error because the apple table exists but it doesn't have 5 records.

Running Changeset: changelog.mysql.xml::1692599548266-1::wesome
Running Changeset: changelog.mysql.xml::1692599548266-2::wesome

Unexpected error running Liquibase: Migration failed for changeset changelog.mysql.xml::1692599548266-2::wesome:
     Reason:
          changelog.mysql.xml : Table apple does not have the expected row count of 5. It contains 0 rows
  - Caused by: Preconditions Failed

Custom message for Preconditions Fail

Liquibase provides an onFailMessage attribute to provide custom messages when an error occurs.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions onFailMessage="condition fail:- apple table should have minimum 5 rows">
			<rowCount expectedRows="5" tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Gala" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

Preconditions onFail attributes

To deal with Preconditions failure scenarios, Liquibase provides an onFail attribute, that controls what should happen if Preconditions doesn't pass onFail supports CONTINUE, HALT, MARK_RAN, WARN. Let's see them one by one.

Preconditions onFail Continue

onFail=CONTINUE will skip the current ChangeSet and will continue with the next ChangeSet in the ChangeLog file. Liquibase will try to execute this ChangeSet on the next update.

In the below example ChangeSet id="1692599548266-2 checking if the table already has 1 record, but since it is a new table, there will not be any record, and Precondition fails.
but with onFail="CONTINUE" , liquibase migrator will skip the ChangeSet and continue execution of the next ChangeSet.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions onFail="CONTINUE" onFailMessage="condition fail:- apple table should have minimum 5 rows">
			<rowCount expectedRows="5" tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Gala" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

Preconditions onFail Halt

onFail=HALT will abort the execution of the entire ChangeLog file. HALT is the default value of onError.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions onFail="HALT" onFailMessage="condition fail:- apple table should have minimum 5 rows">
			<rowCount expectedRows="5" tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Gala" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

Preconditions onFail MARK RAN

onFail=MARK_RAN will skip the execution of the current ChangeSet but it will mark the current ChangeSet as executed in DATABASECHANGELOG table, and continue with the next ChangeSet.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions onFail="MARK_RAN" onFailMessage="condition fail:- apple table should have minimum 5 rows">
			<rowCount expectedRows="5" tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Gala" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

Even though the ChangeSet has failed, it still is marked as executed successfully and can be verified by running a query

select * from appledb.DATABASECHANGELOG;

Preconditions onFail WARN

onError=WARN will send a warning about a failed Preconditions, it will skip the current ChangeSet execution, but mark it as executed in DATABASECHANGELOG table and continue executing the next ChangeSet.

<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
	<changeSet author="wesome" id="1692599548266-1">
		<createTable catalogName="appledb" tableName="apple">
			<column autoIncrement="true" name="apple_id" type="BIGINT">
				<constraints nullable="false" primaryKey="true" />
			</column>
			<column name="apple_name" type="VARCHAR(255)" />
			<column defaultValueComputed="CURRENT_TIMESTAMP" name="current_date_time" type="datetime" />
		</createTable>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-2">
		<preConditions onFail="WARN" onFailMessage="condition fail:- apple table should have minimum 5 rows">
			<rowCount expectedRows="5" tableName="apple" />
		</preConditions>
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Macintosh" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
	<changeSet author="wesome" id="1692599548266-3">
		<insert catalogName="appledb" tableName="apple">
			<column name="apple_id" />
			<column name="apple_name" value="Gala" />
			<column name="current_date_time" valueDate="now()" />
		</insert>
	</changeSet>
</databaseChangeLog>

liquibase.properties (update changeLog File file format with SQL, XML, YAML, JSON as per changelog.mysql.)

changeLogFile=changelog.mysql.xml
liquibase.command.url:jdbc:mysql://localhost:3306/appleDb?createDatabaseIfNotExist=true&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true
liquibase.command.username : root
liquibase.command.password : rootroot

Liquibase will print the warning on the log as well

Running Changeset: changelog.mysql.xml::1692599548266-1::wesome
Running Changeset: changelog.mysql.xml::1692599548266-2::wesome
WARNING: Executing changelog.mysql.xml::1692599548266-2::wesome despite precondition failure due to onFail='WARN':
 condition fail:- apple table should have minimum 5 rows
Running Changeset: changelog.mysql.xml::1692599548266-3::wesome

The ChangeSet has been marked as executed and can be verified by running the query

select * from appledb.DATABASECHANGELOG;

follow us on