{"record":{"id":"c8ad2b68a6dc8dcb","repo":"hibernate/hibernate-orm","slug":"operand-of-op-getoperatorsqltext-is-of-t-c8ad2b","errorCode":null,"errorMessage":"Operand of \" + op.getOperatorSqlText() + \" is of type '\" + rightNodeType.getTypeName() + \"' which is not a temporal amount (it is not an instance of 'java.time.TemporalAmount')","messagePattern":"Operand of \" \\+ op\\.getOperatorSqlText\\(\\) \\+ \" is of type '\" \\+ rightNodeType\\.getTypeName\\(\\) \\+ \"' which is not a temporal amount \\(it is not an instance of '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":540,"sourceCode":"\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) {\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","sourceCodeStart":522,"sourceCodeEnd":558,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java#L522-L558","documentation":"When the left operand of + or - is a java.time.TemporalAmount (Duration/Period), HQL only permits another TemporalAmount on the right: durations combine with durations. Any other right-hand type (number, string, date) fails this SemanticException during query parsing.","triggerScenarios":"`e.duration - 1` (subtracting a plain number); `e.warranty + current_date`; `(e.endDate - e.startDate) + e.name`; `e.duration + 'PT2H'` (string literal instead of a duration literal).","commonSituations":"Trying to shorten/lengthen a duration with an integer (`duration - 30` instead of `duration - 30 day`); mixing up the rule that dates plus durations work but durations plus numbers do not; porting native SQL INTERVAL expressions from PostgreSQL/Oracle to HQL.","solutions":["Combine only duration with duration: `e.warranty - 30 day`","To scale a duration, multiply with the NUMBER on the left: `2 * e.duration`","For date/datetime arithmetic keep the date on the left: `e.dueDate + 3 day`","Use proper HQL duration literals (`3 day`, `2 hour`) instead of plain integers or strings"],"exampleFix":"// before\nselect e.warranty - 30 from Contract e\n\n// after\nselect e.warranty - 30 day from Contract e","handlingStrategy":"try-catch","validationCode":"// Before combining duration expressions, confirm both are TemporalAmount\nstatic boolean isDuration(Attribute<?, ?> a) {\n    return java.time.temporal.TemporalAmount.class.isAssignableFrom(a.getJavaType());\n}","typeGuard":"static boolean durationMathOk(Class<?> left, Class<?> right, String op) {\n    if (java.time.temporal.TemporalAmount.class.isAssignableFrom(left)) {\n        return (\"+\".equals(op) || \"-\".equals(op))\n            && java.time.temporal.TemporalAmount.class.isAssignableFrom(right);\n    }\n    return true; // other cases handled by their own guards\n}","tryCatchPattern":"try {\n    return em.createQuery(hql, Duration.class).getResultList();\n} catch (org.hibernate.query.SemanticException e) {\n    throw new QueryBuildException(\"Duration +/- requires a duration operand: \" + hql, e);\n}","preventionTips":["Combine durations only with durations (`e.warranty - 30 day`, not `- 30`)","Scale durations by putting the number on the LEFT of '*'","Prefer typed CriteriaBuilder expressions over string HQL for duration math"],"tags":["hql","jpql","type-checking","duration","temporal-amount","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"}