{"record":{"id":"0035e694490ba66d","repo":"hibernate/hibernate-orm","slug":"operand-of-op-getoperatorsqltext-is-of-t-0035e6","errorCode":null,"errorMessage":"Operand of \" + op.getOperatorSqlText() + \" is of type '\" + leftNodeType.getTypeName() + \"' which is not a numeric type (it is not an instance of 'java.lang.Number')","messagePattern":"Operand of \" \\+ op\\.getOperatorSqlText\\(\\) \\+ \" is of type '\" \\+ leftNodeType\\.getTypeName\\(\\) \\+ \"' which is not a numeric type \\(it is not an instance of 'java\\.lang\\.Number'\\)","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java","lineNumber":547,"sourceCode":"\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) {\n\t\t\t\t\tcase ADD:\n\t\t\t\t\tcase SUBTRACT:\n\t\t\t\t\t\t// we can add/subtract durations\n\t\t\t\t\t\tif ( !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 temporal amount (it is not an instance of '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\tthrow new SemanticException(\n\t\t\t\t\t\t\t\t\"Operand of \" + op.getOperatorSqlText() + \" is of type '\" + leftNodeType.getTypeName() +\n\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);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( Temporal.class.isAssignableFrom( leftJavaType )\n\t\t\t\t\t|| java.util.Date.class.isAssignableFrom( leftJavaType ) ) {\n\t\t\t\t// left operand is a date, time, or datetime\n\t\t\t\tswitch (op) {\n\t\t\t\t\tcase ADD:\n\t\t\t\t\t\t// we can add a duration to date, time, or datetime\n\t\t\t\t\t\tif ( !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 temporal amount (it is not an instance of '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;","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java#L529-L565","documentation":"When the left operand is a TemporalAmount (duration) but the operator is anything other than + or - (i.e. *, /, %), assertOperable rejects the expression and the message names the LEFT operand's type as 'not a numeric type'. Hibernate only defines scaling for durations via multiplication with the number on the LEFT, so `duration * n` is illegal while `n * duration` is fine.","triggerScenarios":"`e.duration * 2`; `(e.endDate - e.startDate) * 1.5`; `e.duration / 2`; `e.period % 7` — any *, /, or % whose left side is a Duration/Period attribute or duration expression.","commonSituations":"Scaling a computed duration such as `(end - start) * 2` — very common in reporting queries; PostgreSQL habit where `interval * int` and `int * interval` both work; developers confused because the error points at the left operand's type.","solutions":["Swap the operands so the number comes first: `2 * e.duration`","Rewrite `(e.endDate - e.startDate) * 1.5` as `1.5 * (e.endDate - e.startDate)`","If you need the duration as a number first, convert with `by`: `(e.endDate - e.startDate) by day * 1.5` — wait, that yields a number; simply scale the numeric result"],"exampleFix":"// before\nselect (e.endDate - e.startDate) * 2 from Booking e\n\n// after\nselect 2 * (e.endDate - e.startDate) from Booking e","handlingStrategy":"validation","validationCode":"// When scaling durations programmatically, always order number first\nstatic String scale(String durationExpr, String factor) {\n    // '2 * duration' is valid; 'duration * 2' is not\n    return factor + \" * (\" + durationExpr + \")\";\n}","typeGuard":null,"tryCatchPattern":"try {\n    return session.createQuery(hql).list();\n} catch (org.hibernate.query.SemanticException e) {\n    if (e.getMessage().contains(\"not a numeric type\")) {\n        throw new QueryBuildException(\"Move the numeric factor to the LEFT of '*': \" + hql, e);\n    }\n    throw e;\n}","preventionTips":["Canonical rule: multiplication with a duration always reads `number * duration`","Review any query copied from PostgreSQL that multiplies intervals both ways","Unit-test duration-scaling queries against H2/PostgreSQL in CI"],"tags":["hql","type-checking","duration","operator-order","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"}