hibernate/hibernate-orm · error · SemanticException

Illegal operator for a duration {}

Error message

Illegal operator for a duration {}

What it means

transformDurationArithmetic handles only duration algebra with ADD, SUBTRACT and MULTIPLY-with-scalar-on-the-left; any other operator hitting the switch default throws this SemanticException. Effectively: durations can be added/subtracted and scaled by a scalar, but not divided, modulo'd, or multiplied by another duration.

Source

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

				// -x * (d1 - d2) => - x * d1 + x * d2
				inferrableTypeAccessStack.push( () -> determineValueMapping( rhs, fromClauseIndex ) );
				final Expression duration = toSqlExpression( lhs.accept( this ) );
				inferrableTypeAccessStack.pop();
				final Expression scale = adjustmentScale;
				final boolean negate = negativeAdjustment;
				adjustmentScale = applyScale( duration );
				negativeAdjustment = false; //was sucked into the scale
				try {
					inferrableTypeAccessStack.push( () -> determineValueMapping( lhs, fromClauseIndex ) );
					return rhs.accept( this );
				}
				finally {
					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'

View on GitHub (pinned to fad1729dce)

Solutions

  1. Express division of a duration as multiplication by a fraction: 'dur * 0.5'
  2. Extract a scalar first (e.g. via 'extract(epoch from ...)' style functions) and do plain numeric math
  3. Move the operation so the duration only ever appears with +, -, or scalar *

Example fix

// before
select (o.closedAt - o.openedAt) / 2 from Ord o

// after
select (o.closedAt - o.openedAt) * 0.5 from Ord o
Defensive patterns

Strategy: try-catch

Validate before calling

if (isDurationExpr(operand) && (operator == '/' || operator == '%' )) {
    throw new IllegalArgumentException("Duration supports only +, - and scalar *; use dur * 0.5");
}

Try / catch

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

Prevention

When it happens

Trigger: HQL dividing a duration ('(ts1 - ts2) / 2' after normalization in some versions), applying modulo to a duration, or multiplying two duration expressions together; negated duration constructs that fall through to an unhandled operator.

Common situations: Computing averages or ratios of time spans in report queries; porting SQL like 'datediff(...) / 7' to HQL duration syntax; refactors that change operand order so the duration lands under an unsupported operator.

Related errors


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