liquibase Validation Failed: change set checksums changed - how to clear checksums
How to handle liquibase's "Validation Failed: change set checksums changed": deciding whether the edit was safe and clearing stale checksums, or rolling back and writing a new changeset when it was not. Use when validate fails because an applied changeset's content changed. Not for lock problems or changesets that never applied.
TL;DR
An applied changeset was edited, so its checksum no longer matches the recorded one. If the edit was cosmetic or otherwise safe and already ran everywhere, run liquibase clear-checksums so the new checksums are stored on the next update. If the edit changed semantics, roll the changeset back and write a new one instead of rewriting history. Validate after either path.
The query
liquibase Validation Failed: change set checksums changed - how to clear checksumsUse this when
- liquibase validate fails with "change set checksums changed"
- A changeset file was edited after it was applied
- Deploys fail validation on a changeset that used to pass
- An agent "fixed" a changeset in place
Not for
- Changesets that never applied (just edit them freely)
- The changelog lock being stuck (release the lock first)
- A changeset that fails on apply (fix the SQL, not the checksum)
Steps
1. Identify the changed changesets
liquibase validateExpected output: validate names the changeset ids whose checksums differ. Note each id and the file it lives in.
2. Diff each one against what was applied
git log --oneline -- [changelog file]
git diff [commit when applied] HEAD -- [changelog file]Expected output: the exact edits. Classify each: cosmetic (whitespace, comments, formatting) versus semantic (different SQL, different preconditions). Cosmetic edits are clear-checksums candidates; semantic edits are not.
3. Case A: cosmetic or safely-already-applied - clear the checksums
liquibase clear-checksums
liquibase updateExpected output: clear-checksums nulls the stored checksums, and the next update recomputes and stores the current ones. Validate then passes. Only take this path when every environment already ran the edited content.
4. Case B: semantic change - roll back and write a new changeset
liquibase rollback-count 1Then restore the original changeset file from version control and add a NEW changeset with the intended change. Expected output: history is linear again, and the new changeset applies everywhere uniformly. Rewriting an applied changeset is how environments diverge silently.
5. Alternative for intentional edits: validCheckSum
If the edit was deliberate and you want future validates to accept exactly this content, add a validCheckSum entry to the changeset listing the new checksum instead of clearing all checksums. Expected output: validate passes for this changeset while every other changeset's checksum remains enforced.
6. Verify
liquibase validateExpected output: validation succeeds with no checksum errors. Add a CI rule: applied changesets are immutable.
Tool compatibility
liquibase 4.x. validate, clear-checksums, and validCheckSum work the same across 4.x.
Variant phrasings
liquibase Validation Failed change set checksums changed
Steps 1 through 3: identify, classify the edit, clear checksums only for safe edits.
liquibase clear-checksums when to use
Step 3: use it when the edit is cosmetic or already ran everywhere; never as a reflex for semantic changes.
liquibase validCheckSum example
Step 5: declare the new checksum explicitly when the edit was intentional, instead of blanking every checksum.
Why it happens
Liquibase checksums each changeset at apply time and re-verifies on validate, so the recorded history always describes exactly what ran. An edited changeset breaks that guarantee: different environments may have run different SQL under the same id. Validation fails to force a human to reconcile the divergence.
Edge cases
- clear-checksums is global: it re-baselines every changeset, so a second, genuinely wrong edit hides inside the same operation. Prefer validCheckSum for single intentional edits.
- Line-ending normalization in the repo changes every checksum at once: fix line endings once, clear once, and enforce with .gitattributes.
- If the semantic edit already ran in production, you cannot roll it back cleanly: write a compensating changeset that undoes or corrects the production state, and document the divergence.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst_q7isY5r7vufZGBDCgN1foA