{"record":{"id":"9d3b592edd3f33e7","repo":"hibernate/hibernate-orm","slug":"operand-of-like-is-of-type-nodetype-gettype","errorCode":null,"errorMessage":"Operand of 'like' is of type '\" + nodeType.getTypeName() + \"' which is not a string (its JDBC type code is not string-like)","messagePattern":"Operand of 'like' is of type '\" \\+ nodeType\\.getTypeName\\(\\) \\+ \"' which is not a string \\(its JDBC type code is not string-like\\)","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java","lineNumber":620,"sourceCode":"\t}\n\n\tpublic static boolean isNumberArray(@Nullable SqmExpressible<?> expressible) {\n\t\tif ( expressible != null ) {\n\t\t\tfinal var domainType = expressible.getSqmType();\n\t\t\tif ( domainType != null ) {\n\t\t\t\treturn domainType instanceof BasicPluralType<?, ?> basicPluralType\n\t\t\t\t\t&& Number.class.isAssignableFrom( basicPluralType.getElementType().getJavaType() );\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static void assertString(SqmExpression<?> expression) {\n\t\tfinal var nodeType = expression.getNodeType();\n\t\tif ( nodeType != null ) {\n\t\t\tif ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )\n\t\t\t\t\t|| !jdbcMapping.getJdbcType().isStringLike() ) {\n\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\"Operand of 'like' is of type '\" + nodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\"' which is not a string (its JDBC type code is not string-like)\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void assertDuration(SqmExpression<?> expression) {\n\t\tfinal var nodeType = expression.getNodeType();\n\t\tif ( nodeType != null ) {\n\t\t\tif ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )\n\t\t\t\t\t|| !jdbcMapping.getJdbcType().isDuration() ) {\n\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\"Operand of 'by' is of type '\" + nodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\"' which is not a duration (its JDBC type code is not duration-like)\"\n\t\t\t\t);\n\t\t\t}\n\t\t}","sourceCodeStart":602,"sourceCodeEnd":638,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java#L602-L638","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Cast the operand to string: `cast(e.year as string) like '20%'`","Restrict like-filters to attributes whose Java type is String (check via JPA metamodel)","Store searchable codes (zip, phone) as String columns instead of numeric","For date prefix matching use range predicates (`>= and <`) instead of like"],"exampleFix":"// before (zipCode is Integer)\nwhere e.zipCode like '94%'\n\n// after\nwhere cast(e.zipCode as string) like '94%'","handlingStrategy":"type-guard","validationCode":"// Only attach a like-filter when the attribute is a String\nSingularAttribute<?, ?> attr = mm.entity(Account.class).getSingularAttribute(field);\nif (!String.class.equals(attr.getJavaType())) {\n    // fall back to equality or cast\n    return cb.equal(root.get(field), value);\n}\nreturn cb.like(root.get(field), value + \"%\");","typeGuard":"static boolean isStringAttr(Attribute<?, ?> attr) {\n    return String.class.equals(attr.getJavaType());\n}","tryCatchPattern":"try {\n    return em.createQuery(hql).getResultList();\n} catch (org.hibernate.query.SemanticException e) {\n    throw new QueryBuildException(\"'like' needs a string operand — cast(e.x as string): \" + hql, e);\n}","preventionTips":["In global-search UIs, restrict like filters to String-typed attributes","Store searchable codes (zip, phone, year) as String columns","For numeric prefix matching use cast(attr as string) like or range predicates"],"tags":["hql","like","type-checking","string-cast","hibernate-6"],"backgroundTag":"query-operand-type-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}