hibernate/hibernate-orm · error · SemanticException

Operand of 'like' is of type '" + nodeType.getTypeName() + "

Error message

Operand of 'like' is of type '" + nodeType.getTypeName() + "' which is not a string (its JDBC type code is not string-like)

What it means

TypecheckUtil.assertString (invoked from SemanticQueryBuilder when parsing `like`) requires the left operand's SQM type to be a JdbcMapping whose JdbcType is string-like (CHAR/VARCHAR family). Applying `like` to a numeric, date, boolean, UUID, or enum column fails this SemanticException at query-translation time.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java:620

	}

	public static boolean isNumberArray(@Nullable SqmExpressible<?> expressible) {
		if ( expressible != null ) {
			final var domainType = expressible.getSqmType();
			if ( domainType != null ) {
				return domainType instanceof BasicPluralType<?, ?> basicPluralType
					&& Number.class.isAssignableFrom( basicPluralType.getElementType().getJavaType() );
			}
		}
		return false;
	}

	public static void assertString(SqmExpression<?> expression) {
		final var nodeType = expression.getNodeType();
		if ( nodeType != null ) {
			if ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )
					|| !jdbcMapping.getJdbcType().isStringLike() ) {
				throw new SemanticException(
						"Operand of 'like' is of type '" + nodeType.getTypeName() +
								"' which is not a string (its JDBC type code is not string-like)"
				);
			}
		}
	}

	public static void assertDuration(SqmExpression<?> expression) {
		final var nodeType = expression.getNodeType();
		if ( nodeType != null ) {
			if ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )
					|| !jdbcMapping.getJdbcType().isDuration() ) {
				throw new SemanticException(
						"Operand of 'by' is of type '" + nodeType.getTypeName() +
								"' which is not a duration (its JDBC type code is not duration-like)"
				);
			}
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Cast the operand to string: `cast(e.year as string) like '20%'`
  2. Restrict like-filters to attributes whose Java type is String (check via JPA metamodel)
  3. Store searchable codes (zip, phone) as String columns instead of numeric
  4. For date prefix matching use range predicates (`>= and <`) instead of like

Example fix

// before (zipCode is Integer)
where e.zipCode like '94%'

// after
where cast(e.zipCode as string) like '94%'
Defensive patterns

Strategy: type-guard

Validate before calling

// Only attach a like-filter when the attribute is a String
SingularAttribute<?, ?> attr = mm.entity(Account.class).getSingularAttribute(field);
if (!String.class.equals(attr.getJavaType())) {
    // fall back to equality or cast
    return cb.equal(root.get(field), value);
}
return cb.like(root.get(field), value + "%");

Type guard

static boolean isStringAttr(Attribute<?, ?> attr) {
    return String.class.equals(attr.getJavaType());
}

Try / catch

try {
    return em.createQuery(hql).getResultList();
} catch (org.hibernate.query.SemanticException e) {
    throw new QueryBuildException("'like' needs a string operand — cast(e.x as string): " + hql, e);
}

Prevention

When it happens

Trigger: `where e.year like '20%'` with e.year an Integer; `e.id like :pattern`; `e.createdAt like '2024-01%'`; generic 'search all fields' UIs that attach `like` to any property the user types into.

Common situations: Global search filters applied blindly to numeric IDs and dates; ZIP codes, phone numbers, or years stored as numeric columns but searched with prefix matching; works on some databases via implicit casts in native SQL, then breaks when moved to strict HQL or a stricter Hibernate 6 version.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/9d3b592edd3f33e7. Report an issue: GitHub.