- Concept
- Version · 6.0
- Troubleshoot
Error codes and exit codes
Last updated: September 29, 2026
When a Liquibase command fails, it reports the failure two ways: a process exit code that tells your pipeline the command did not succeed, and, for most failures, a stable error code and a suggested next step printed to STDERR.
The two are linked. The same failure that supplies the printed LB- code decides the exit code, so the console output and the process status can never disagree.
Exit codes
Liquibase returns 0 when a command succeeds and a nonzero code when it fails. Treat any nonzero exit code as a failure.
Before 6.0 every failure returned 1. In 6.0 a failure can return a more specific code, decided in this order:
If a changeset or flow file set an explicit exit code, through an
onFailexit action or a flowexitCode:, that code wins.Otherwise, if the failure carries an
LB-error code, its classification decides the exit code. A user-attributable failure returns1; an infrastructure or internal failure returns70.A failure that carries no error code returns
1, whatever its underlying cause.
Which failures return a specific code grows as more of the product moves to the new error model. Do not write a pipeline that treats one exit code as meaning one thing. Branch on success versus failure, and let anything nonzero be a failure.
Error message format
A failure that carries an error code prints one line on STDERR, followed by a suggestion:
Before 6.0, the same failure printed Unexpected error running Liquibase: <message>.
Not every failure carries a code yet. The reference below lists every code Liquibase 6.0 ships. A failure that has not been migrated still prints the
Unexpected error running Liquibase:prefix followed by theException Details / Primary Class / Reason / Sourceblock. The message body is the same in both forms. That legacy block is how you can tell a failure path has no code yet.A coded failure prints once. The
Exception Detailsblock does not accompany a coded error. Full stack traces appear only at--log-level=FINE.Codes are stable. Once a code exists, its meaning does not change. A code can be deprecated and replaced, but a number is never reused.
If you parse Liquibase error output, this is the part that breaks. Matching on ^Unexpected error running Liquibase: no longer catches a coded failure. Match on the message body, or on the LB- code:
Codes and messages are CLI-only
The exit-code contract and the coded messages apply to the Liquibase CLI. The Maven goal fails the build by throwing, and the Spring integration propagates the exception. Neither consults the CLI exit map, and neither prints a code or a suggestion. If you drive Liquibase through Maven or Spring, none of this changes for you.
Error code reference
A code has the form LB-<DOMAIN>-<NNNN>. The domain says which subsystem raised the failure.
Domain | Covers | Codes |
|---|---|---|
CHG | Changelog and changeset parsing and validation | 39 |
CMD | CLI and command layer | 36 |
PRE | Preconditions | 12 |
LCK | Lock service | 7 |
RLB | Rollback | 8 |
LIC | Licensing | 25 |
TRK | Usage tracking | 2 |
DBO | Database object and snapshot operations | 4 |
FLW | Flow orchestration | 5 |
EXE | Native executors used by runWith | 5 |
CHK | Policy checks engine | 23 |
DBX | Database driver and connection layer | 5 |
SYS | Infrastructure, classpath, and service loading | 2 |
MGO | MongoDB | 1 |
AWS | DynamoDB and S3 | 9 |
CBS | Couchbase | 3 |
In the tables below, … marks a value Liquibase substitutes at runtime, such as a file name, a changeset ID, or the underlying driver message.
CHG: Changelog and changeset parsing
Code | What it means | What to do |
|---|---|---|
| The changelog file was not found on the search path. | Verify the changelog path (relative to the search path) and your --search-path setting, then retry. |
| Error Reading Changelog File: … | Verify the file is readable by the Liquibase process and not locked by another program, then retry. |
| Changelog '…' contains a DOCTYPE declaration, which is not supported. Liquibase changelogs validate against XSD schemas and do not support DOCTYPE/DTD declarations. Remove the <!DOCTYPE> block from your changelog. | Delete the <!DOCTYPE ...> block from the changelog file; the xmlns/xsi:schemaLocation attributes on <databaseChangeLog> are all Liquibase needs. |
| Unable to parse empty file: '…' | Add at least one changeset to the changelog, or remove the empty file from your include/includeAll path. |
| Error parsing line … column … of …: … | Fix the XML at the reported line/column; the parser message describes what was expected. |
| Invalid Migration File: … | Validate the changelog against its XSD schema (an IDE with XML validation shows the offending element inline). |
| Could not find databaseChangeLog node | The YAML/JSON changelog must have a top-level 'databaseChangeLog:' key. Check indentation and spelling. |
| databaseChangeLog does not contain a list of entries. Each changeSet must begin ' - changeSet:' | Make databaseChangeLog a YAML list: every entry starts with '- ' (e.g. '- changeSet:'), consistently indented. |
| Error parsing … : … | See the underlying parser message for the failing construct, fix the changelog, and retry. |
| Syntax error in file …: … | Fix the YAML syntax at the location the parser reports (indentation and ':' placement are the usual culprits). |
| A line in a formatted changelog is not a recognized directive. Renders the parser's description of the offending line. | Fix the flagged directive line to one of the documented formatted-changelog forms (see https://docs.liquibase.com/concepts/changelogs/sql-format.html), then re-run the command. |
| Unknown ignoreLines syntax: "…" | Use '--ignoreLines:<count>' with a positive integer, or '--ignoreLines:start' ... '--ignoreLines:end' to delimit a block. |
| No … for changeset … | Every changeset in a formatted changelog needs a statement body under its '--changeset' header. Add the missing statements or remove the empty changeset. |
| '…' not set in rollback block '…' | Rollback references need both changesetId and changesetAuthor (e.g. '--rollback changesetId:1 changesetAuthor:me'). Add the missing attribute. |
| Change set … does not exist | The rollback block references a changeset that is not in this changelog. Check the changesetId, changesetAuthor and changesetPath values against the target changeset. |
| Liquibase rollback comment is not closed. | Close the '/* liquibase rollback' comment block with '*/' before the next changeset or end of file. |
| Cannot parse … as a boolean | The attribute accepts only 'true' or 'false'. Fix the value on the flagged changeset header. |
| The '…' precondition type is not supported. | Formatted SQL changelogs support the sql-check, table-exists and view-exists inline preconditions. Use one of those, or move the precondition to an XML/YAML changelog. |
| An inline precondition is missing required parameters. | Provide every required parameter for the inline precondition (e.g. expectedResult and sql for sql-check; table-name for table-exists; view-name for view-exists). |
| Could not parse a SqlCheck precondition from '…'. | Use the form '--precondition-sql-check expectedResult:<value> <sql>' on a single line. |
| A tableExists or viewExists precondition body is invalid: a name or schema is missing or repeated. | Specify exactly one table-name/view-name (and at most one schema-name) in the tableExists/viewExists precondition body. |
| A Pro-only formatted-SQL directive was used without a valid license. | This directive is a Pro feature: set a valid license key (liquibase.licenseKey) and retry, or remove the directive. Get a trial key at https://liquibase.com/trial. |
| An includeAll directive has an invalid minDepth or maxDepth value. | minDepth/maxDepth on includeAll must be integers greater than 0 (and minDepth <= maxDepth). Fix the value on the flagged directive. |
| Could not assemble the include/includeAll directive: … | See the underlying cause for the failing attribute, fix the include/includeAll parameters in the formatted changelog, and retry. |
| No path attribute included in '…' | The file directive requires a path attribute, e.g. '--file path:my/script.sql'. Add the path to the flagged line. |
| The changelog parsed, but Liquibase could not build a changelog from it. Renders the underlying failure. | Review the underlying cause and the changelog's structure (element ordering, attribute types), then retry. |
| Unexpected error parsing XML changelog: … | See the underlying cause. If this recurs, capture the changelog and the full stack trace (--log-level=DEBUG) for a bug report. |
| Could not find … file: …! Make sure the value of the … is a valid path to a file containing the …'s actual value to be loaded. | The path is resolved relative to the changelog file that declares the changeset. Fix the valueBlobFile/valueClobFile attribute to point at an existing file, and confirm the file is reachable via your search path (--search-path). |
| Cannot convert string value '…' to …: … | Fix the attribute value on the flagged changeset so it is a valid …; the parse error above names the offending character. |
| Cannot parse expression … | Balance the parentheses in the context/label expression and use only the documented operators (and, or, not, '!', ','), then rerun. |
| runOrder must be 'first' or 'last', but was '…' | Set runOrder to 'first' or 'last' on the flagged changeset, or drop the attribute to keep the changelog's declared order. |
| Unknown boolean value: … | Boolean columns accept true/false, 1/0 or the database's own boolean literal. Correct the value in the changeset (or, for loadData, declare the column's type as BOOLEAN so the CSV value is parsed first). |
| Cannot parse the SQL in …: … | Fix the flagged character or token in that changeset's SQL. The message names the file line range and the lexer detail names the exact character. If the SQL is valid for your database, the tokenizer may not support that syntax; isolate the statement in its own changeset and report the failing snippet. |
| The SQL in … contains a character that could not be decoded (U+FFFD): … | U+FFFD means the file's bytes do not match the charset Liquibase used to read it. This is an encoding mismatch, not a SQL error. Re-save the changelog file as UTF-8, or set 'fileEncoding' (liquibase.fileEncoding / LIQUIBASE_FILE_ENCODING) to the file's actual encoding, then rerun. |
| Changelog validation failed. See STDOUT for the full list of validation errors. | Fix the reported issues in your changelog (typically duplicate changeset ids, checksum mismatches, or failed preconditions) and re-run 'liquibase validate'. |
| Rollback marker at line … has no preceding forward statement to attach to. | Move the '--rollbackSQL' marker below the forward SQL it undoes, or remove it if the preceding statement was intentionally deleted. |
| Raw SQL input '…' contains a bare … inside a PL/SQL block at …. Liquibase's per-changeset transaction contract cannot survive an in-block …: Oracle honors it before Liquibase can veto the failed changeset, silently double-applying committed side effects on rerun (COMMIT) or leaving the deploy un-resumable (ROLLBACK). | Remove the in-block … at … so the whole changeset can complete atomically. If the block legitimately requires independent transaction control (e.g. PRAGMA AUTONOMOUS_TRANSACTION), pass '--allow-in-block-txn-control=true' to decorate-sql to opt this file out of the check. |
| Raw SQL input '…' has a GO batch at … that declares a T-SQL variable and also contains the statement at …, which SQL Server requires to be the only statement in its batch. The batch cannot be combined into one changeset without producing SQL the server rejects. | Put the statement at … in its own GO batch, or wrap the variable-dependent statements in BEGIN..END so they form a single statement, then re-run decorate-sql. |
| Raw SQL input '…' contains the transaction-control statement … at line(s) …, which a changelog cannot reproduce. Liquibase runs each changeset in its own transaction, so the statements this one governs land in different changesets than the statement itself: a savepoint never survives to the changeset that would roll back to it, and a transaction mode cannot govern the statements that follow. Decorating this file would remove the statement and produce a changelog that deploys different data than the original script. | Remove the transaction-control statement at line(s) … of '…', or restructure the script so the work it guards is one statement group that Liquibase can roll back as a unit - a failed changeset is rolled back on its own, which is what a savepoint was protecting against. If the statement is left over from an earlier script and losing it is acceptable, pass '--allow-txn-control-loss=true' to decorate-sql: the statement is still removed, but the command completes and warns instead of failing. |
CMD: CLI and command layer
Code | What it means | What to do |
|---|---|---|
| Invalid argument '…': missing required argument | Provide the missing argument on the command line, in your defaults file (liquibase.<argument>), or as a LIQUIBASE_* environment variable. |
| Invalid argument '…': missing required argument | If you need to configure new liquibase project files and arguments, run the 'liquibase init project' command. Otherwise provide the missing argument on the command line or in your defaults file. |
| Output ChangeLogFile '…' already exists! | Pass --overwrite-output-file=true to replace the existing file, or choose a different --changelog-file name. |
| Invalid types for --run-on-change-types: … | Remove the unsupported types, or pass only change types that support runOnChange (or 'none'). See 'liquibase generate-changelog --help'. |
| Invalid types for --replace-if-exists-types: … | Remove the unsupported types, or pass only change types that support replaceIfExists (or 'none'). See 'liquibase generate-changelog --help'. |
| Serializing changelog as sql requires a file name in the format *.databaseType.sql. Example: changelog.….sql. Passed: … | Rename the output changelog file to match *.<databaseType>.sql (for example changelog.h2.sql) so Liquibase can infer the SQL dialect. |
| You must specify the changeset ID, author, and path | Provide --changeset-id, --changeset-author, and --changeset-path on the command line. |
| ERROR: The '--changeset-path' value must be a valid relative path and filename to the changelog-file containing the single changeset to deploy. | Use a relative path without '.' or '..' segments that points at the changelog file containing the changeset. |
| WARNING: Targeted update of this changeset may result in unexpected outcomes. If this is a SQL database, you may review the update SQL before executing it by running 'update-one-changeset-sql'. This message can be suppressed by adding the --force flag. | Review the SQL with 'update-one-changeset-sql', then re-run the command with --force. |
| WARNING: Targeted rollback of this changeset may result in unexpected outcomes. If this is a SQL database, you may review the rollback SQL before executing it by running 'rollback-one-changeset-sql'. This message can be suppressed by adding the --force flag. | Review the SQL with 'rollback-one-changeset-sql', then re-run the command with --force. |
| The number of schemas in '…' (…) does not match the number in '--schemas' (…). | Pass the same number of comma-separated schemas to '--schemas' and '…', in matching order. |
| generate-changelog would overwrite the existing stored-logic files in '…'. | Remove or rename that directory, or point --changelog-file at a location whose 'objects' sibling does not exist yet, then rerun. |
| The output file '…' cannot be written: …. | Point '--changelog-file' at a writable file location. The path resolves against the current working directory. Check for a mistyped directory name, and create missing directories or fix their permissions before rerunning. |
| Unknown database type '…' in changelog file name '…'. Serializing changelog as sql requires the file name segment to match a recognised Liquibase database short name. | Rename the file to use a valid database short name segment (for example changelog.….sql). Available database short names: … |
| Cannot serialize object type: … | Formatted-SQL changelogs can only hold changesets. Remove the unsupported element, or serialize to XML/YAML/JSON by giving '--changelog-file' a matching extension. |
| You must specify the changelog file name as filename.DB_TYPE.sql. Example: changelog.mysql.sql | Pass '--changelog-file' a name whose second-to-last extension is the database type (for example 'changelog.mysql.sql') so Liquibase can pick the SQL dialect to serialize. |
| Cannot specify both excludeObjects and includeObjects | These two filters are mutually exclusive. Keep either excludeObjects or includeObjects on the Ant task and delete the other, then rerun the build. |
| Cannot parse the value '…' configured for '…' as a … | Correct '…' wherever you set it (CLI flag, defaults file, or LIQUIBASE_* environment variable) so that it reads as a … value. Run 'liquibase --help' to see each argument's expected type. |
| Input file for … not found: '…' | Verify the … path exists and is readable, or place it under a configured --search-path entry, then re-run 'decorate-sql'. |
| --changelogFile '…' names database type '…' but the resolved database dialect is '…'. | Rename the output to *.….sql, or to a name with no database-type segment such as changelog.sql. The decorate-sql command takes the dialect from --url/--dbType, not from the file name. Then re-run 'decorate-sql'. |
| --dbType '…' is not supported. Valid values: … | Pass --dbType with one of … and re-run 'decorate-sql'. |
| --executor '…' is not supported. Valid values: … (or omit --executor for JDBC). | Pass --executor with one of …, or omit --executor to run via JDBC. |
| --executor '…' is only valid with --dbType '…', but --dbType '…' was passed. | Use --dbType=… to keep --executor=…, omit --executor to run via JDBC, or pass an executor that matches --dbType=…. |
| Cannot infer output format from '…'. Supported extensions: … | Rename --changelogFile to end with one of … and re-run 'decorate-sql'. |
| Unable to resolve --changelogFile '…': … | Check that the --changelogFile path is reachable and readable by the current process. |
| Unable to read --rollbackFile '…': … | Verify the --rollbackFile path exists, is readable, and is reachable from the current --search-path. |
| --url '…' resolves to database dialect '…', but --dbType '…' names a different dialect. | Drop --dbType to trust the URL's dialect, change --dbType to '…', or supply a --url for '…' and re-run 'decorate-sql'. |
| decorate-sql requires either --url or --dbType to determine the database dialect for classification. | Pass --dbType=oracle or --dbType=mssql, or supply --url=<jdbc:...> to infer the dialect from the URL prefix (no connection is opened). |
| --url '…' does not identify a database dialect supported by decorate-sql. Supported: … | Pass --dbType=oracle or --dbType=mssql explicitly, or supply a JDBC URL for a supported vendor. |
| Input file '…' contains bytes that are not valid … text. | Re-save '…' as …, or set --file-encoding to the encoding the file actually uses (for example --file-encoding=windows-1252 for a Windows-1252 file), then re-run 'decorate-sql'. |
| Input file '…' was read as … and contains NUL characters, so it is not valid SQL text. | If '…' is UTF-16 with no byte-order mark, set --file-encoding to its encoding (for example --file-encoding=UTF-16LE), then re-run 'decorate-sql'. Otherwise remove the NUL characters from the file. |
| Input file '…' declares … with a byte-order mark but contains bytes that are not valid … text. | The byte-order mark in '…' selects … and overrides --file-encoding, so the file itself is malformed - it is most likely truncated or two files concatenated. Re-save '…' from its source, then re-run 'decorate-sql'. |
| Input file '…' declares … with a byte-order mark but contains NUL characters, so it is not valid SQL text. | The byte-order mark in '…' selects … and overrides --file-encoding, so setting that flag will not change how the file is read. The file is most likely a … byte-order mark followed by content in another encoding - re-save '…' from its source in a single encoding, then re-run 'decorate-sql'. |
| The --rollback-file '…' contains no executable SQL - it is empty, or holds only comments or whitespace. | A changeset whose rollback does nothing would report a successful rollback while leaving the change in place, so 'decorate-sql' refuses it. If '…' should have content, check the step that generated it. If this changeset genuinely reverses to nothing, say so explicitly - put … in '…' - then re-run 'decorate-sql'. |
| The --sql-file '…' contains no executable SQL - it is empty, or holds only comments or whitespace. | There is nothing to decorate, and 'decorate-sql' would otherwise write a changelog that deploys nothing. Check the step that generated '…', then re-run 'decorate-sql' against a file containing at least one SQL statement. |
| No changesets could be produced from the --sql-file '…'. | Decorating '…' yielded nothing to deploy, so 'decorate-sql' refuses rather than writing an empty changelog. If the file is empty or holds only comments, check the step that generated it. If an advisory above names a line number, fix that line first - a malformed '--rollbackSQL' marker is the usual reason a file with content still produces no changesets. |
PRE: Preconditions
Code | What it means | What to do |
|---|---|---|
| A precondition requiring a database object was not met: the expected object does not exist. | Confirm the object was created by an earlier changeset (or exists in the target), fix its name/schema/catalog in the precondition, or set an onFail policy (MARK_RAN / CONTINUE / WARN) if its absence is expected. |
| A tableIsEmpty precondition was not met: the table is not empty. | If the table is expected to hold rows, remove the tableIsEmpty precondition or set an onFail policy; otherwise truncate/clear the table before this changeset runs. |
| A runningAs precondition was not met: the current database user is not the expected one. | Connect as the username the precondition expects, or update the runningAs username to match the account Liquibase runs under. |
| A rowCount precondition was not met: the table's row count differs from the expected value. | Adjust the expectedRows value, or ensure the data-loading changesets that populate the table run before this precondition. |
| A customPrecondition could not be evaluated or reported failure. | Verify the customPrecondition class is on the classpath, its parameters are valid, and its check() logic. See the underlying cause for details. |
| A changeSetExecuted precondition was not met: the referenced changeset has not been run. | Confirm the changeset id/author/changelog match a previously deployed changeset, or run it first; use 'liquibase history' to see what has been applied. |
| A dbms precondition was not met: the target database type differs from the expected one. | Run against the expected DBMS, or fix the dbms precondition's 'type' value (comma-separated for multiple) to include the target. |
| A sqlCheck precondition was not met: the query returned no rows or a value other than the expected result. | Verify the sqlCheck SQL and its expectedResult, and that the objects it queries exist in the target before this changeset runs. |
| A changeLogPropertyDefined precondition was not met: the property is unset or its value differs from the expected one. | Define the changelog property (property name/value, a -D flag, or a defaults-file entry) so it matches, or fix the precondition's expected value. |
| An objectQuotingStrategy precondition was not met: the changeset's quoting strategy differs from the expected one. | Set the changeset's objectQuotingStrategy to the expected value, or update the precondition to the strategy actually in use. |
| A not precondition was not met: its nested precondition(s) evaluated to true. | Invert or adjust the nested precondition(s) inside the <not> block so the intended condition is expressed. |
| A precondition is present while generating SQL and 'onUpdateSQL' is set to '…', which fails the run. | Set onUpdateSQL to TEST to evaluate the precondition, or IGNORE to skip it, when running an *-sql command. |
LCK: Lock service
Code | What it means | What to do |
|---|---|---|
| Could not acquire change log lock. Currently locked by … | Another Liquibase process holds the changelog lock. If you are certain no other process is running, run 'liquibase release-locks' to clear stale lock records, then retry. |
| Did not update change log lock correctly while acquiring the lock | The DATABASECHANGELOGLOCK table returned an unexpected update count. Run 'liquibase release-locks' to reset it, then retry your command. |
| Error acquiring the change log lock | Verify database connectivity and that the current user can write to the DATABASECHANGELOGLOCK table, then retry. See the underlying cause for details. |
| Did not update change log lock correctly. … rows were updated instead of the expected 1 using executor …; there are … rows in the table | The DATABASECHANGELOGLOCK table is in an unexpected state. Run 'liquibase release-locks' to reset it, then retry your command. |
| Error releasing the change log lock | Verify database connectivity and permissions on the DATABASECHANGELOGLOCK table, then run 'liquibase release-locks' to clear any stale lock. |
| Error listing the change log locks | Verify database connectivity and that the DATABASECHANGELOGLOCK table is readable, then retry. |
| Service […] is not an owner of this lock ([…]) | The lock is held by another service instance. Wait for the owner to release it, or run 'liquibase release-locks' to force-clear a stale lock if you are sure the owner is gone. |
RLB: Rollback
Code | What it means | What to do |
|---|---|---|
| No inverse to … created | This change type cannot generate an automatic rollback. Add an explicit <rollback> block to the changeset, or mark it with failOnError or runOnChange as appropriate. |
| … is not supported on … | The generated inverse change is not supported on this database. Provide an explicit <rollback> block in the changeset for this database. |
| Error generating rollback statements | Review the changeset's <rollback> definition and the underlying cause, then retry. A custom rollback may be required. |
| Unknown rollback type: … | The custom change's rollback must implement a supported rollback interface. Review the customChange class and its rollback contract. |
| WARNING: The rollback script '…' was not located. Please check your parameters. No rollback was performed. | Check the --rollback-script path (relative to the working directory / search path), or remove the argument to use the changeset's own rollback. |
| Error reading rollbackScript …: … | Verify the rollback script is readable by the Liquibase process and not locked by another program, then retry. |
| No deployment IDs were located. No rollbacks were performed. | Run 'liquibase history' to list valid deployment IDs, then pass one via --deployment-id (or confirm any changesets have been deployed to this target). |
| Cannot roll back renameViewColumnsAndUpdateBody on view '…': 'oldBody' is required to restore the previous view definition. | Re-apply the changeset with 'oldBody' set to the view's prior SQL body, then retry the rollback. |
LIC: Licensing
Code | What it means | What to do |
|---|---|---|
| Using 'rollback-on-error' requires a valid Liquibase Pro or Labs license. Get a free license key at …. | Add liquibase.licenseKey=<yourKey> into your defaults file or use --license-key=<yourKey> before your command in the CLI. |
| Using '…' requires a valid … license. Get a free license key at …. | Add liquibase.licenseKey=<yourKey> into your defaults file or use --license-key=<yourKey> before your command in the CLI. |
| A license-gated command ran without a valid license. Renders the license service message, which names the command. | If you have not set a key yet, follow the instructions above. If you believe you already set one, run 'liquibase --version' to see which licence Liquibase actually resolved - it prints the key's expiry and tier, which is how an expired key or a Labs-only key on a Secure command shows up. LIQUIBASE_LICENSE_KEY is also read from the environment. |
| The license file could not be verified against any trusted key (tried …). Source: …. | Download the license file again from the Liquibase portal, and check it was issued for this product: the keys this build trusts are named by fingerprint above, and a file signed by anything else cannot be verified here. |
| The license file uses algorithm '…', which Liquibase does not accept. | Re-export the license file with algorithm base64+ed25519. Encrypted checkouts are not accepted because their key derivation is not FIPS-approved. |
| The license file could not be read: …. Source: …. | Download the license file again from the Liquibase portal and copy it whole, including the BEGIN LICENSE FILE and END LICENSE FILE lines. In a properties file, end every line of it with a backslash so the value continues on the next line, or set liquibase.licenseFile to the path of the downloaded file instead. |
| This license file states kind '…', which cannot license an installation on its own. | Use a consolidated license file, or point … at your Secure Server or lightweight license service, which resolve the base and its add-ons together. |
| No usable license verify key is available in this Liquibase build. | Reinstall Liquibase from an official distribution; the verify key is built in and this one carries none that can be read. |
| Could not read a license from the license endpoint … (…), and no cached license is available. | Check that the license endpoint is reachable from this host and answering. Once one response has been received it is cached, and a later outage falls back to it. |
| The license data from the license endpoint … went stale on …; it was obtained on … and has not been replaced with fresher data. The license term runs to …. | Check that the license endpoint is reachable and serving current data; a reachable endpoint answering with an old issuedAt produces this too. Nothing about the license has changed; only this copy of it has gone stale. |
| The license endpoint speaks license-access contract version … and this version of Liquibase implements version …. | Upgrade Liquibase to a version that reads contract version …, or point … at a service that serves version …. |
| The license endpoint … did not answer with a readable license (…). | Check that … points at the license-access endpoint of Secure Server or the lightweight license service, and not at another page on the same host. |
| The value of … is not a URL this JVM can request. | Set … to an absolute http or https URL, for example https://secure-server.example.com/api/licensing/access. |
| The configured license is neither a Liquibase 6 license file nor a valid earlier license (…). Source: …. | A Liquibase 6 license file begins with -----BEGIN LICENSE FILE-----; copy it whole from the Liquibase portal. For a license key issued before Liquibase 6, check that it was copied whole and has not expired. |
| The license data reports that it was issued at …, which is later than this machine's current time of …. | Check the clock on this host and on the license endpoint. Liquibase allows up to five minutes of difference before treating license data as impossible; until the clocks agree it cannot tell fresh data from data that would never expire. |
| The Liquibase Secure license expired on …. | Renew the license and install the new file, or point … at a service that serves the renewed one. Grace, when the license states any, has already ended. |
| The license file in … states no expiration date, so Liquibase cannot tell whether it is in force. | Download the license file again from the Liquibase portal. A Liquibase 6 license states its term; only a license issued before Liquibase 6 may omit it. |
| The license source … reports that this installation is not licensed. The license term runs to …. | The source answered, so this is its verdict rather than a connection problem. Contact your Liquibase account team; if you use a license file, download a fresh one from the Liquibase portal, and if you use an endpoint, check what it serves. |
| No Liquibase Secure license is configured. | Point … at your Secure Server or lightweight license service, set … to the path of a license file downloaded from the Liquibase portal, or … to its contents. Any one of them licenses this installation. Run 'liquibase license status' to see what Liquibase resolved. |
| The license file … could not be read: …. | Check that liquibase.licenseFile names the license file downloaded from the Liquibase portal; a relative path is resolved against the directory Liquibase runs in. To pass the file's content instead of its path, use liquibase.licenseKey. |
| The license endpoint … answered without any signed license, so nothing it states can be verified. | Upgrade the license service at … to one that publishes the signed license files with its response, or point … at one that does. A response without them cannot be told apart from one anybody could write. |
| A license file served by … was not accepted: …. | Check that … points at this installation's own license service, and that the licenses installed on it were issued by Liquibase. A license file this build cannot verify is not one it can be licensed by, whatever the response says about it. |
| The license endpoint … claims … that the signed licenses do not grant: …. | Check that … serves this installation's own licenses. A response claiming more than its licenses grant has either been altered in transit or was not built from the files it serves. |
| The license endpoint … refused this request because … does not hold a key it accepts. | Set … to an API key issued by that installation. A server configured with LICENSE_ACCESS_REQUIRE_API_KEY=true accepts no unauthenticated request. |
| The value configured in … cannot be sent as an HTTP header: it contains a control character, or a character outside plain ASCII that would go on the wire as a question mark and reach the server as a different key. | Re-copy … from where it was issued: the key itself must be plain ASCII. Ordinary spaces, tabs and line endings around it are stripped before this check, so what is refused is either a character inside the value or an unusual one around it, such as a carriage return from a file edited on Windows, or a non-breaking space or curly quote from a word processor. |
TRK: Usage tracking
Code | What it means | What to do |
|---|---|---|
| Usage tracking to … failed after … tries and … is set: …. | Check that the usage tracking collector at … is reachable from this machine, or unset … to let the run continue with a warning. Set liquibase.license.tracking.spoolDir to keep the usage payload for replay on the next run. |
| The usage tracking collector address in … is not a URL Liquibase can request: …. | Set … to the collector's base address, scheme included, for example https://llt.example.com:8080. In endpoint mode the address served by the license endpoint is used instead and this setting is not read. |
DBO: Database objects and snapshots
Code | What it means | What to do |
|---|---|---|
| Cannot parse snapshot '…' for offline database '…' | Check that the file named by the offline URL's 'snapshot=' parameter exists, is readable, and was produced by 'liquibase snapshot --snapshot-format=json'; the underlying cause names the parse failure. |
| Unsupported database for check constraint snapshot: … | Check constraints are snapshotted on PostgreSQL, Oracle, MySQL, SQL Server, DB2 LUW and DB2 for z/OS only. Drop 'checkConstraint' from the diff/snapshot types for this database, or run the command against a supported one. |
| … | Inspect the drift details above (or re-run with --format=JSON) for the objects between '…' and '…', then either reconcile the schemas or raise --drift-severity / --drift-severity-missing / --drift-severity-changed / --drift-severity-unexpected if this level of drift is expected. |
| Cannot run '…' against the offline database '…' | Offline connections store changelog history in the local file named by the URL's 'changeLogFile' parameter, and this command would delete or overwrite it instead of a real database. Run '…' against the real JDBC URL instead of the offline: URL. |
FLW: Flow orchestration
Code | What it means | What to do |
|---|---|---|
| Cannot set 'continueOnError' to true when using the exit command. | Remove 'continueOnError: true' from the exit action in your flow file. |
| Command cannot be empty. | Set the 'command:' property of the flow action to a Liquibase command name. |
| Circular references between flow files are not allowed. | Remove the flow action that invokes this flow file from itself, directly or through an included flow file. |
| Error opening file '…': … | Verify the flow file path exists and is readable, or pass --flow-file with the correct location. |
| Command … is not allowed in flow files. | Remove the forbidden command from the flow file and run it directly from the CLI instead. |
EXE: Native executors
Code | What it means | What to do |
|---|---|---|
| A runWith:sqlplus execution was stopped by compiler warnings or errors. | SQL Plus compiler warnings/errors stopped this job because the fail-options setting is '…' (it may come from … or from your liquibase.sqlplus.conf file). To control which severities stop the job, set … to one of: …. Learn more at https://docs.liquibase.com/secure/reference-guide-5-2/sqlplus-fail-options |
| The executable for the native executor 'psql' cannot be found at path '…' as specified in the liquibase.psql.conf file, the LIQUIBASE_PSQL_* environment variables, or other config locations. Learn more at https://docs.liquibase.com/pro/integration-guide/use-native-executors-with-postgresql. | Point liquibase.psql.path (or the LIQUIBASE_PSQL_PATH environment variable) at the psql binary, or install the PostgreSQL client tools so psql is on your PATH, then rerun. |
| The executable for the native executor 'sqlplus' cannot be found at path '…' as specified in the liquibase.sqlplus.conf file. Please specify the correct path for the 'sqlplus' executable, or modify your PATH so that it can be located. Learn more at http://docs.liquibase.com. | Point liquibase.sqlplus.path in liquibase.sqlplus.conf (or the LIQUIBASE_SQLPLUS_PATH environment variable) at the sqlplus binary, or install Oracle Instant Client with SQL*Plus so it is on your PATH, then rerun. |
| The 'sqlcmd' executable was not found at '…'. Please check the liquibase.sqlcmd.path property in liquibase.sqlcmd.conf, the LIQUIBASE_SQLCMD_PATH Environment variable, or other config locations. Learn more at https://docs.liquibase.com/pro/integration-guide/use-the-sqlcmd-integration-with-multiple-databases. | Point liquibase.sqlcmd.path (or the LIQUIBASE_SQLCMD_PATH environment variable) at the sqlcmd binary, or install the SQL Server command-line tools so sqlcmd is on your PATH, then rerun. |
| Invalid timeout value of '…' | Set the native executor timeout to a positive whole number of seconds, or to -1 to run without a timeout. |
CHK: Policy checks engine
Code | What it means | What to do |
|---|---|---|
| Invalid argument 'changelogFile, url': one is required for 'checks run' | Provide --changelog-file to run changelog checks, --url to run database checks, or both. |
| Invalid argument '…': you must supply a changelogFile argument for changelog checks | Add --changelog-file, or remove 'changelog' from --checks-scope to run database checks only. |
| Invalid argument '…': you must supply a URL argument for database checks | Add --url, or remove 'database' from --checks-scope to run changelog checks only. |
| Invalid argument '…': The 'changeset-filter' property is set to 'pending', and 'checks-scope' to 'database' which results in no matches to inspect. Please adjust your filters. Learn more at …. | Include 'changelog' in --checks-scope so pending changesets can be inspected, or drop 'pending' from --changeset-filter. |
| Invalid argument '…': you must supply a URL argument with a pending changeset filter | Add --url so pending changesets can be resolved against the database's DATABASECHANGELOG history. |
| Invalid argument '…': you cannot specify an offline database with a pending changeset filter | Use a live database --url; resolving pending changesets requires querying the DATABASECHANGELOG table, which offline mode cannot do. |
| … | Policy checks reached severity … against '…'. If that failure level is not expected, adjust the failing check's severity in the checks settings file '…', or resolve the reported violation(s) and re-run 'checks run'. |
| --assignment-id was supplied, but no Liquibase Platform connection is configured (missing …) | Set liquibase.platform.apiUrl to your server's ingest URL and liquibase.platform.apiKey to a workspace API key with access to the assignment, as an environment variable, in your properties file, or as a system property. |
| Invalid argument 'assignmentId' value '…': … | Pass one assignment UUID, or a comma-separated list of at most 50 assignment UUIDs. |
| Liquibase Platform at '…' rejected the request to pull checks settings by assignment id: … | Check that liquibase.platform.apiKey is a valid, unexpired workspace API key with access to the requested assignment(s). |
| No such assignment(s) were found for uuid(s) '…': … | Confirm the assignment UUID(s) in Change Governance, and that your API key's workspace owns them. An archived assignment produces this error too. |
| Pulling checks settings by assignment id from the Liquibase Platform at '…' failed: … | Check liquibase.platform.apiUrl and network connectivity, then retry. If the server is unavailable, use --checks-settings-file with a local file instead. |
| Invalid argument 'assignmentId': checks configured in the Liquibase Platform's Governance module cannot be edited in the CLI | Manage this check's settings in Change Governance. |
| Liquibase could not parse the checks settings file pulled from the Liquibase Platform for assignment(s) '…': … | Retry the pull. If it keeps failing, review the assignment's checks configuration in Change Governance, or fall back to --checks-settings-file with a local file. |
| Invalid Liquibase Platform URL derived from liquibase.platform.apiUrl ('…'): … | Check that liquibase.platform.apiUrl is a valid, fully qualified URL with a scheme and a host. |
| Pulling checks settings by assignment id from the Liquibase Platform at '…' returned a page rather than a checks settings file: … | Something in front of the platform answered instead of the platform, most often an authentication proxy or SSO gateway intercepting the request. The governance endpoint authenticates with its own API key, so it needs to be reachable without that interception. Confirm the endpoint answers directly, for example: curl -s -o /dev/null -w '%%{http_code}' -H 'Authorization: Bearer invalid' '<your-api-root>/governance/checks-settings-file?assignment_uuids=x' should return 401, not 302 or 200. |
| Invalid argument combination: '--python-scripts=include' requires '--linked-checks-files=include' | Set --linked-checks-files=include to bundle the custom check scripts together with their checks-settings files, or set --python-scripts=exclude to keep both as links. |
| The custom check script '…' referenced by check '…' could not be found, so it cannot be bundled into the export artifact | Fix the check's script-path, make the script available on the search path or --checks-scripts-path, or set --python-scripts=exclude to export the checks without bundling their scripts. |
| Invalid argument 'format' value '…': supported checks export artifact formats are 'zip', 'tar' and 'targz' | Pass --format=zip, --format=tar or --format=targz. The file-extension spellings '.zip', '.tar' and '.tar.gz' are accepted as well. |
| Invalid argument '…' value '…': expected 'include' or 'exclude' | Pass 'include' to bundle the files into the export artifact, or 'exclude' to keep them referenced as links. |
| Liquibase could not write the checks export artifact to '…': … | Check that the destination path is writable, is not an existing directory, and has enough free space, then run 'checks export' again. Use --export-file to write somewhere else. |
| The checks package '…' lists '…', which is itself a checks package file, and nested checks package files are not supported by 'checks export' | List the checks-settings files of '…' directly in '…' instead of the package file itself, or run 'checks export --checks-settings-file=…' to export that package on its own. |
| The custom check script '…' referenced by check '…' could not be read, so it cannot be bundled into the export artifact: … | Point the check's script-path at a readable script file rather than a directory or a path that matches more than one search-path root, narrow --checks-scripts-path to the directory holding the script, or set --python-scripts=exclude to export the checks without bundling their scripts. |
DBX: Database driver and connection layer
Code | What it means | What to do |
|---|---|---|
| The database rejected the connection because of the credentials or the account state. | The database rejected the credentials. Verify --username and --password (or the URL-embedded credentials), and that the account is not locked or expired. |
| The driver could not open a connection: unreachable host, refused port, TLS or handshake failure, or timeout. | Verify the JDBC URL host/port, that the database is running and reachable from this machine, and that the driver matches the target database. The underlying driver message has the specifics. |
| The driver returned no connection, which means no registered driver matches the URL prefix. | The driver did not recognize this JDBC URL. Check the URL prefix against the driver documented for your database, and that the intended driver is on the classpath. |
| A SQL statement failed while executing against an open connection. | The database rejected this statement, not the connection. Run the failing SQL directly against the database to see the full server-side context; if it references a missing object, run 'liquibase status' to confirm the changesets that create it were deployed and were not filtered out by contexts or labels. |
| Cannot determine the Oracle database version number | Liquibase needs the server version to choose the identifier length limit (30 bytes before 12cR2, 128 after). Confirm the connection is still open and that the Liquibase user can read PRODUCT_COMPONENT_VERSION / V$VERSION; the underlying cause carries the driver's message. |
SYS: Infrastructure and classpath
Code | What it means | What to do |
|---|---|---|
| Cannot find … for … | Nothing on the classpath supports this database. Install the Liquibase extension for it (drop its jar in the 'lib' directory, or add the dependency to your build) and rerun; 'liquibase --version' lists what is currently loaded. |
| Cannot determine resource path for … | Liquibase stores this path in DATABASECHANGELOG, so it fails rather than guess. Reference the changelog through a stable 'classpath:' location (or move it to the classpath root) and rerun. |
MGO: MongoDB
Code | What it means | What to do |
|---|---|---|
| The MONGODB-AWS authentication handshake failed. | Verify the AWS identity Liquibase is using with 'aws sts get-caller-identity', refresh expired credentials (or set AWS_SESSION_TOKEN for temporary ones), and confirm that role ARN is registered as an $external user on the cluster. |
AWS: DynamoDB and S3
Code | What it means | What to do |
|---|---|---|
| Connection to … was unsuccessful. Please check your configuration properties. | Verify the AWS credentials, region, and endpoint in your DynamoDB URL and provider chain (run 'aws sts get-caller-identity' to confirm the active identity), then retry. |
| Table '…' wasn't … with timeout=… s and number of retries=… (…) | If this was a timeout, the DynamoDB operation may still complete afterwards: inspect the table for the last expected changeset and run 'liquibase changelogsync' if the changes are present, or increase liquibase.dynamodb.waiter.*.totalTimeout / set liquibase.dynamodb.waiters.failOnTimeout=false. For credential or network failures, see the underlying cause included in the message. |
| Table '…' did not reach the expected state while being … | The DynamoDB waiter reported a failure (see the underlying cause). Verify the table state in the AWS console and your permissions for DescribeTable, then retry. |
| Liquibase DynamoDB Extension does not support … commands Please refer to our documentation for the entire list of supported commands for DynamoDB | Run this command against a database target that supports it, or consult the DynamoDB extension documentation for the list of supported commands. |
| A changeset exceeds the DynamoDB transaction limits. | Split the change into multiple changesets, or set runInTransaction="false" on the changeset so its statements execute outside the single-transaction limit. |
| Tracking write would exceed DynamoDB transaction limits (… items / ~… MB). DynamoDB supports max 100 items and 4 MB per transaction. | Reduce the number or size of statements in the changeset so the DATABASECHANGELOG tracking write fits in the same transaction, or set runInTransaction="false" on the changeset. |
| DynamoDB transaction failed: … | Inspect the cancellation reasons and the underlying cause, fix the failing condition or oversized item, and re-run the command. Changesets that already committed are not re-applied. |
| Could not … | See the underlying cause for the DynamoDB SDK error. Verify the statement is valid PartiQL and the target table exists (check with 'aws dynamodb list-tables'). |
| liquibase-commercial-dynamodb extension cannot execute changeset Unknown type: … | The changeset uses a change or statement type the DynamoDB extension does not implement. Rewrite it as raw PartiQL (a sql change) or use a supported change type. |
CBS: Couchbase
Code | What it means | What to do |
|---|---|---|
| Index … on collection … already exists over …, so Liquibase cannot create the index its tracking queries need. | Drop or rename that index, or replace it with one whose leading key is meta().id, then re-run the command. |
| Interrupted while waiting for the query service to catalogue collection …, so its Liquibase index was not created. | No changes were deployed. Re-run the command to finish provisioning the tracking collection. |
| Liquibase Couchbase Extension does not support … Please refer to our documentation for the entire list of supported commands for Couchbase | Run this command against a database target that supports it, or consult the Couchbase extension documentation for the list of supported commands. |
When Liquibase writes structured logs, a coded failure also records its error code and suggestion as logging keys. See What are structured logging keys?.