hibernate/hibernate-orm · error · SemanticException

Operand of " + op.getOperatorSqlText() + " is of type '" + l

Error message

Operand of " + op.getOperatorSqlText() + " is of type '" + leftNodeType.getTypeName() + "' which is not a numeric type (it is not an instance of 'java.lang.Number')

What it means

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.

Source

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

						}
						break;
				}
			}
			else if ( TemporalAmount.class.isAssignableFrom( leftJavaType ) ) {
				// left operand is a duration
				switch (op) {
					case ADD:
					case SUBTRACT:
						// we can add/subtract durations
						if ( !TemporalAmount.class.isAssignableFrom( rightJavaType ) ) {
							throw new SemanticException(
									"Operand of " + op.getOperatorSqlText() + " is of type '" + rightNodeType.getTypeName() +
											"' which is not a temporal amount (it is not an instance of 'java.time.TemporalAmount')"
							);
						}
						break;
					default:
						throw new SemanticException(
								"Operand of " + op.getOperatorSqlText() + " is of type '" + leftNodeType.getTypeName() +
										"' which is not a numeric type (it is not an instance of 'java.lang.Number')"
						);
				}
			}
			else if ( Temporal.class.isAssignableFrom( leftJavaType )
					|| java.util.Date.class.isAssignableFrom( leftJavaType ) ) {
				// left operand is a date, time, or datetime
				switch (op) {
					case ADD:
						// we can add a duration to date, time, or datetime
						if ( !TemporalAmount.class.isAssignableFrom( rightJavaType ) ) {
							throw new SemanticException(
									"Operand of " + op.getOperatorSqlText() + " is of type '" + rightNodeType.getTypeName() +
											"' which is not a temporal amount (it is not an instance of 'java.time.TemporalAmount')"
							);
						}
						break;

View on GitHub (pinned to fad1729dce)

Solutions

  1. Swap the operands so the number comes first: `2 * e.duration`
  2. Rewrite `(e.endDate - e.startDate) * 1.5` as `1.5 * (e.endDate - e.startDate)`
  3. 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

Example fix

// before
select (e.endDate - e.startDate) * 2 from Booking e

// after
select 2 * (e.endDate - e.startDate) from Booking e
Defensive patterns

Strategy: validation

Validate before calling

// When scaling durations programmatically, always order number first
static String scale(String durationExpr, String factor) {
    // '2 * duration' is valid; 'duration * 2' is not
    return factor + " * (" + durationExpr + ")";
}

Try / catch

try {
    return session.createQuery(hql).list();
} catch (org.hibernate.query.SemanticException e) {
    if (e.getMessage().contains("not a numeric type")) {
        throw new QueryBuildException("Move the numeric factor to the LEFT of '*': " + hql, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


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