{"record":{"id":"845f0de5b71c1958","repo":"hibernate/hibernate-orm","slug":"operand-of-op-getoperatorsqltext-is-of-t","errorCode":null,"errorMessage":"Operand of \" + op.getOperatorSqlText() + \" is of type '\" + rightNodeType.getTypeName() + \"' which is not a numeric type (it is not an instance of 'java.lang.Number' or 'java.time.TemporalAmount')","messagePattern":"Operand of \" \\+ op\\.getOperatorSqlText\\(\\) \\+ \" is of type '\" \\+ rightNodeType\\.getTypeName\\(\\) \\+ \"' which is not a numeric type \\(it is not an instance of 'java\\.lang\\.Number' or 'java\\.time\\.TemporalAmount'\\)","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java","lineNumber":517,"sourceCode":"\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void assertOperable(SqmExpression<?> left, SqmExpression<?> right, BinaryArithmeticOperator op) {\n\t\tfinal var leftNodeType = left.getExpressible();\n\t\tfinal var rightNodeType = right.getExpressible();\n\t\tif ( leftNodeType != null && rightNodeType != null ) {\n\t\t\tfinal var leftJavaType = leftNodeType.getRelationalJavaType().getJavaTypeClass();\n\t\t\tfinal var rightJavaType = rightNodeType.getRelationalJavaType().getJavaTypeClass();\n\t\t\tif ( Number.class.isAssignableFrom( leftJavaType ) ) {\n\t\t\t\t// left operand is a number\n\t\t\t\tswitch (op) {\n\t\t\t\t\tcase MULTIPLY:\n\t\t\t\t\t\tif ( !Number.class.isAssignableFrom( rightJavaType )\n\t\t\t\t\t\t\t\t// we can scale a duration by a number\n\t\t\t\t\t\t\t\t&& !TemporalAmount.class.isAssignableFrom( rightJavaType ) ) {\n\t\t\t\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\t\t\t\"Operand of \" + op.getOperatorSqlText() + \" is of type '\" + rightNodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\t\t\t\"' which is not a numeric type (it is not an instance of 'java.lang.Number' or 'java.time.TemporalAmount')\"\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif ( !Number.class.isAssignableFrom( rightJavaType ) ) {\n\t\t\t\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\t\t\t\"Operand of \" + op.getOperatorSqlText() + \" is of type '\" + rightNodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\t\t\t\"' which is not a numeric type (it is not an instance of 'java.lang.Number')\"\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( TemporalAmount.class.isAssignableFrom( leftJavaType ) ) {\n\t\t\t\t// left operand is a duration\n\t\t\t\tswitch (op) {","sourceCodeStart":499,"sourceCodeEnd":535,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java#L499-L535","documentation":"Hibernate 6's HQL/JPQL semantic analyzer type-checks every binary arithmetic expression via TypecheckUtil.assertOperable before SQL generation. For the '*' operator, when the left operand is a java.lang.Number, the right operand must also be a Number, or a java.time.TemporalAmount (so a duration can be scaled by a number). Any other right-hand type makes the query fail to compile with this SemanticException.","triggerScenarios":"HQL like `select o.price * o.sku from Order o` where o.sku is a String; `where e.age * e.active > 1` (boolean right side); `e.total * e.createdDate`; any multiplication where the left side resolves to a numeric Java type but the right side resolves to String, Boolean, enum, UUID, or a date/time type (only TemporalAmount is exempted, and only for MULTIPLY).","commonSituations":"Numeric-looking codes stored in VARCHAR columns and used in arithmetic; typo'd property names in hand-written HQL; generic filter/sort builders that apply '*' to whatever attribute the caller passes; upgrading from Hibernate 5 or early 6.x where these type checks were absent or looser.","solutions":["Reference the correct numeric attribute on the right side of '*'","If the value lives in a String column, cast it: `e.amount * cast(o.code as double)`","Store the value in a proper numeric column type instead of VARCHAR","In dynamic query builders, verify via the JPA metamodel that the attribute's JavaType is assignable from Number before emitting '*'"],"exampleFix":"// before (o.sku is String)\nselect o.price * o.sku from Order o\n\n// after\nselect o.price * cast(o.sku as double) from Order o","handlingStrategy":"try-catch","validationCode":"// Before building the predicate, verify both operands are numeric\nMetamodel mm = em.getMetamodel();\nSingularAttribute<?, ?> left = mm.entity(Order.class).getSingularAttribute(\"price\");\nSingularAttribute<?, ?> right = mm.entity(Order.class).getSingularAttribute(\"sku\");\nif (!Number.class.isAssignableFrom(left.getJavaType())\n        || !Number.class.isAssignableFrom(right.getJavaType())) {\n    throw new IllegalArgumentException(\"'%' requires numeric operands\");\n}","typeGuard":"static boolean isNumericAttr(Attribute<?, ?> attr) {\n    return Number.class.isAssignableFrom(attr.getJavaType());\n}","tryCatchPattern":"try {\n    return em.createQuery(hql, Long.class).getSingleResult();\n} catch (org.hibernate.query.SemanticException e) {\n    throw new InvalidQueryException(\"Type error in query (check operand types): \" + hql, e);\n}","preventionTips":["Compile all named HQL queries at startup (createNamedQuery on boot) so type errors fail fast in CI, not in production","Keep numeric data in numeric column types; never do arithmetic on VARCHAR columns","In generic filter builders, whitelist arithmetic to attributes whose metamodel JavaType is Number"],"tags":["hql","jpql","type-checking","arithmetic","hibernate-6","semantic-exception"],"backgroundTag":"query-operand-type-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}