Skip to content

Fix Liquibase Changelog Error – Changeset Not Running

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about Fix Liquibase Changelog Error. We cover key concepts, practical examples, and best practices.

You write a Liquibase changeset in XML or YAML, run liquibase update, and the changeset is skipped — or it fails with "Validation error: 'tableName' is required". The changeset looks correct but Liquibase refuses to apply it.

Wrong ❌

<!-- db/changelog/v2-add-users.xml -->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog">
  <changeSet id="2" author="alice">
    <createTable>
      <column name="id" type="int">
        <constraints primaryKey="true"/>
      </column>
      <column name="name" type="varchar(255)"/>
    </createTable>
    <!-- ❌ missing tableName attribute -->
  </changeSet>
</databaseChangeLog>

```bash
liquibase update

Error:

Validation error: 'tableName' is required for createTable

The `createTable` element needs a `tableName` attribute.

## Right ✅

```xml
<!-- db/changelog/v2-add-users.xml -->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                   http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.20.xsd">
  <changeSet id="2" author="alice">
    <createTable tableName="users">
      <column name="id" type="int" autoIncrement="true">
        <constraints primaryKey="true" nullable="false"/>
      </column>
      <column name="name" type="varchar(255)">
        <constraints nullable="false"/>
      </column>
      <column name="email" type="varchar(255)">
        <constraints unique="true"/>
      </column>
    </createTable>
  </changeSet>
</databaseChangeLog>

**YAML format (preferred):**

```yaml
# db/changelog/v2-add-users.yaml
databaseChangeLog:
  - changeSet:
      id: 2
      author: alice
      changes:
        - createTable:
            tableName: users
            columns:
              - column:
                  name: id
                  type: int
                  autoIncrement: true
                  constraints:
                    primaryKey: true
                    nullable: false
              - column:
                  name: name
                  type: varchar(255)
              - column:
                  name: email
                  type: varchar(255)
                  constraints:
                    unique: true

**Include the changelog in the root:**

```xml
<!-- db/changelog-master.xml -->
<databaseChangeLog>
  <include file="changelog/v1-init-schema.xml" relativeToChangelogFile="true"/>
  <include file="changelog/v2-add-users.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

```bash
liquibase --changeLogFile=db/changelog-master.xml update

**If a changeset is skipped:**

Check the `changeSet` attributes:

```xml
<changeSet id="2" author="alice" runOnChange="true">
  <!-- This changeset runs every time it changes (checksum) -->
</changeSet>

<changeSet id="3" author="alice" runAlways="true">
  <!-- This changeset runs on every update -->
</changeSet>

If the changeset has already been applied (recorded in `DATABASECHANGELOG`), Liquibase skips it unless `runAlways="true"`.

## Root Cause

Changesets fail due to missing required attributes or incorrect XML/YAML structure. Changesets are skipped because they were already applied (recorded in the `DATABASECHANGELOG` table).

## Prevention

- Use YAML format  it's easier to validate and less verbose than XML.
- Validate changelogs: `liquibase validate`.
- Use `runOnChange="true"` for changesets that may need re‑execution (views, grants).
- Check the `DATABASECHANGELOG` table to see which changesets are already applied.


## Common Mistakes with changelog error

1. **Using `head` and `tail` instead of pattern matching, causing runtime errors on empty lists**
2. **Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks**
3. **Using `return` to exit a function early instead of wrapping a pure value in the monad**

These mistakes appear frequently in real-world LIQUIBASE code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

## Practice Exercise

**Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.**

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

## FAQ

<details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: What's the difference between `runAlways` and `runOnChange`?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: <code>runAlways</code> runs on every update. <code>runOnChange</code> runs only when the changeset's MD5 checksum changes.</p>
</div></details><details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: Can I use SQL directly in a changeset?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: Yes  use <code>&lt;sql&gt;</code> tag or a SQL file: <code>&lt;sqlFile path=&quot;my.sql&quot;/&gt;</code>.</p>
</div></details><details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: How do I rollback a changeset?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: Define a <code>&lt;rollback&gt;</code> section in the changeset. Then <code>liquibase rollbackCount 1</code>.</p>
</div></details><details style="margin-bottom:12px;border:1px solid #e2e8f0;border-radius:10px;overflow:hidden"><summary style="cursor:pointer;padding:14px 18px;font-weight:600;font-size:1.05rem;background:#f8fafc;border-bottom:1px solid #e2e8f0;color:#1e293b">**Q: Why does Liquibase say "No changes found"?**</summary><div style="padding:14px 18px;color:#475569;line-height:1.7;background:#fff"><p>A: All changesets are already applied. Use <code>liquibase status --verbose</code> to see details.</p>
</div></details>

---

*Liquibase changelogs are covered in the [DodaTech Liquibase Fundamentals course](https://dodatech.com/courses/liquibase).*

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro