hibernate/hibernate-orm · error · SemanticException

Illegal operator for temporal type: {}

Error message

Illegal operator for temporal type: {}

What it means

When both operands of a binary arithmetic expression are temporal (date/time/timestamp), the only defined operation is SUBTRACT, which produces a duration. Any other operator between two temporal values is ill-formed and rejected with a SemanticException naming the operator.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/sql/spi/BaseSqmToSqlAstConverter.java:7286

					inferrableTypeAccessStack.pop();
					adjustmentScale = scale;
					negativeAdjustment = negate;
				}
			default:
				throw new SemanticException( "Illegal operator for a duration " + operator );
		}
	}

	private Object transformDatetimeArithmetic(SqmBinaryArithmetic<?> expression) {
		final var operator = expression.getOperator();

		// the only kind of algebra we know how to
		// do on dates/timestamps is subtract them,
		// producing a duration - all other binary
		// operator expressions with two dates or
		// timestamps are ill-formed
		if ( operator != SUBTRACT ) {
			throw new SemanticException( "Illegal operator for temporal type: " + operator );
		}

		// a difference between two dates or two
		// timestamps is a leaf duration, so we
		// must apply the scale, and the 'by unit'
		// ts1 - ts2

		final var lhs = SqmExpressionHelper.getActualExpression( expression.getLeftHandOperand() );
		final var rhs = SqmExpressionHelper.getActualExpression( expression.getRightHandOperand() );

		final var fromClauseIndex = fromClauseIndexStack.getCurrent();
		inferrableTypeAccessStack.push( () -> determineValueMapping( rhs, fromClauseIndex ) );
		final var left = getActualExpression( cleanly( () -> toSqlExpression( lhs.accept( this ) ) ) );
		inferrableTypeAccessStack.pop();
		inferrableTypeAccessStack.push( () -> determineValueMapping( lhs, fromClauseIndex ) );
		final var right = getActualExpression( cleanly( () -> toSqlExpression( rhs.accept( this ) ) ) );
		inferrableTypeAccessStack.pop();

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use subtraction for span calculations: 'date1 - date2'
  2. Shift timestamps by durations instead: 'ts + 1 day'
  3. Use dialect functions (add_months, dateadd...) via native SQL or function templates for other date combinations

Example fix

// before
select o.dueDate + o.createdOn from Ord o

// after
select o.dueDate - o.createdOn from Ord o
Defensive patterns

Strategy: try-catch

Validate before calling

if (isTemporalPath(left) && isTemporalPath(right) && operator != '-') {
    throw new IllegalArgumentException("Only date1 - date2 is defined between two temporal values");
}

Try / catch

try {
    return session.createQuery(hql).getResultList();
} catch (org.hibernate.query.SemanticException e) {
    log.error("Temporal operator rejected: {}", hql, e);
    throw e;
}

Prevention

When it happens

Trigger: HQL like 'date1 + date2', 'ts1 * ts2', or predicates where two mapped temporal attributes are combined with an operator other than minus.

Common situations: Naive date math ported from scripting languages; generated queries that apply the same arithmetic template to all numeric-looking columns; refactors that swap an operand from a number to a date column without changing the operator.

Related errors


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