YunaiV/ruoyi-vue-pro · error · UnexpectedLiquibaseException

Unknown boolean value: {}

Error message

Unknown boolean value: {}

What it means

Liquibase BooleanType.sqlToJava or equivalent string parsing rejects a value that is not recognized as true, false, or a Postgres bit-string literal. The branch list accepts 'true'/'1', 'false'/'0'/'f', and Postgres b'...'::bit patterns; anything else (e.g. 't', 'yes', 'Y', 'N', localized strings, null-ish text) reaches the else and throws UnexpectedLiquibaseException.

Source

Thrown at sql/dm/flowable-patch/src/main/java/liquibase/datatype/core/BooleanType.java:85

        }

        String returnValue;
        if (value instanceof String) {
            value = ((String) value).replaceAll("'", "");
            if ("true".equals(((String) value).toLowerCase(Locale.US)) || "1".equals(value) || "b'1'".equals(((String) value).toLowerCase(Locale.US)) || "t".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getTrueBooleanValue(database).toLowerCase(Locale.US))) {
                returnValue = this.getTrueBooleanValue(database);
            } else if ("false".equals(((String) value).toLowerCase(Locale.US)) || "0".equals(value) || "b'0'".equals(
                ((String) value).toLowerCase(Locale.US)) || "f".equals(((String) value).toLowerCase(Locale.US)) || ((String) value).toLowerCase(Locale.US).equals(this.getFalseBooleanValue(database).toLowerCase(Locale.US))) {
                returnValue = this.getFalseBooleanValue(database);
            } else if (database instanceof PostgresDatabase && Pattern.matches("b?([01])\\1*(::bit|::\"bit\")?", (String) value)) {
                returnValue = "b'"
                    + value.toString()
                    .replace("b", "")
                    .replace("\"", "")
                    .replace("::it", "")
                    + "'::\"bit\"";
            } else {
                throw new UnexpectedLiquibaseException("Unknown boolean value: " + value);
            }
        } else if (value instanceof Long) {
            if (Long.valueOf(1).equals(value)) {
                returnValue = this.getTrueBooleanValue(database);
            } else {
                returnValue = this.getFalseBooleanValue(database);
            }
        } else if (value instanceof Number) {
            if (value.equals(1) || "1".equals(value.toString()) || "1.0".equals(value.toString())) {
                returnValue = this.getTrueBooleanValue(database);
            } else {
                returnValue = this.getFalseBooleanValue(database);
            }
        } else if (value instanceof DatabaseFunction) {
            return value.toString();
        } else if (value instanceof Boolean) {
            if (((Boolean) value)) {
                returnValue = this.getTrueBooleanValue(database);

View on GitHub (pinned to 0418084e22)

Solutions

  1. Normalize the boolean value before it reaches BooleanType: use 1/0, true/false, or the DB's canonical boolean keyword.
  2. If you must use 'Y'/'N' or 't'/'f', wrap the column as a non-boolean type (CHAR(1)) in the changeset instead of BOOLEAN.
  3. Register a custom Liquibase DataType to extend the accepted boolean vocabulary for your source DB.
  4. Check the changelog for defaultValueBoolean or valueBoolean with non-canonical text and replace it.

Example fix

// before
<column name="active" type="BOOLEAN" defaultValue="Y"/>
// after
<column name="active" type="BOOLEAN" defaultValueBoolean="true"/>
Defensive patterns

Strategy: validation

Validate before calling

private static final Pattern BOOL = Pattern.compile("^(true|false|0|1|b'0|b'1|t|f)$", Pattern.CASE_INSENSITIVE);
if (value instanceof String && !BOOL.matcher(((String)value)).matches()) {
    throw new IllegalArgumentException("Unrecognized boolean literal: " + value);
}

Type guard

static boolean isLiquibaseBooleanLiteral(Object v) {
    if (!(v instanceof String)) return false;
    String s = ((String)v).toLowerCase(Locale.US);
    return s.equals("true") || s.equals("false") || s.equals("0") || s.equals("1") || s.equals("f") || s.equals("b'0") || s.equals("b'1");
}

Try / catch

try {
    return booleanType.objectToSql(value, db);
} catch (UnexpectedLiquibaseException e) {
    return "0"; // safe default, logged
}

Prevention

When it happens

Trigger: A changelog/column default or raw value supplies a boolean literal the parser does not whitelist ('t'/'yes'/'Y'/'TRUE' on non-Postgres DBs, 'no', 'n', empty string, or a DB-specific boolean keyword); migrating data from a DB whose boolean text differs from the expected set.

Common situations: Porting a schema from PostgreSQL (which uses 't'/'f') to MySQL/Oracle/Dameng; setting column defaultValue='Y'/'N' in a changeset; loading seed data with 'yes'/'no'.

Related errors


AI-assisted analysis of YunaiV/ruoyi-vue-pro@0418084e22 (2026-08-14). Data as JSON: /api/errors/100277a3d12869a1. Report an issue: GitHub.