Liquibase rollback fails with missing rollback definition after addColumn changeset
0 reputation · 26 Feb 2026, 12:14 UTC
0 reputation · 26 Feb 2026, 12:14 UTC
I have a changelog where one changeset adds a column with a default value to an existing table, and a later changeset builds on that column. When I run a rollback command targeting the earlier changeset, Liquibase aborts and reports that no rollback was defined for the changeset, leaving the schema untouched.
My understanding is that Liquibase only reverses a changeset if it contains an explicit <rollback> block, and that some change types can be auto-reversed while others cannot. I am unsure which category addColumn with a default value falls into, and whether the failure I am seeing is purely the missing block or something about how the changeset was written.
A second concern: even once a rollback block exists, dropping the column would also destroy the data it holds, and I have not found a documented built-in mechanism for preserving that data during reversal.
addColumn with a default value require an explicit <rollback> block?35275 reputation · 26 Feb 2026, 21:34 UTC
Liquibase can automatically reverse a changeset only when it uses one of the built‑in change types that are marked as reversible. The <addColumn> change type is one of those; Liquibase will generate a DROP COLUMN statement for you. However, the “missing rollback definition” error appears when Liquibase cannot infer a reverse operation. This usually happens when the column was added with a raw <sql> tag or a <customChange> instead of the structured <addColumn> element. In that case, Liquibase requires an explicit <rollback> block.
addColumn, dropColumn, addPrimaryKey, dropPrimaryKeyaddForeignKeyConstraint, dropForeignKeyConstraintcreateTable, dropTableinsert, delete, update (if rollback is provided)Any change that does not have a reverse, or that is expressed via raw SQL, must be wrapped in a <rollback> block.
Liquibase does not move data for you when a column is dropped. The usual pattern is to copy the column’s contents to an archive table before dropping it. Example:
<changeSet id="2026-10-15-add-new-col" author="me">
<addColumn tableName="orders">
<column name="promo_code" type="varchar(20)" defaultValue="N/A"></column>
</addColumn>
<rollback>
<sql>
CREATE TABLE IF NOT EXISTS orders_promo_code_backup AS
SELECT id, promo_code FROM orders;
</sql>
<dropColumn tableName="orders" columnName="promo_code"/>
</rollback>
</changeSet>
In this block Liquibase first creates a backup table (id + old column value) and then drops the column. Because the <dropColumn> is a reversible change, Liquibase will record the rollback as successful only after the backup table is created.
If Liquibase aborts while executing a rollback, the database remains in the state after the last successful SQL statement. Liquibase updates the DATABASECHANGELOG table only when the entire rollback completes. Therefore:
DATABASECHANGELOG with EXECUTED status.--force or manually delete the row.The error message you see is most common when the column was added with a raw <sql> statement. If that is the case, add an explicit <rollback> block as shown above. If you used <addColumn> correctly, ensure that no later changeset depends on the column you are trying to roll back; Liquibase will refuse to roll back an earlier changeset if a later one references it. In that scenario, roll back the later changeset first.
Diagnostic question for you: Did you add the column using a <sql> tag instead of the structured <addColumn> element? This detail determines whether Liquibase can auto‑reverse the change or requires an explicit rollback block.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.