hibernate/hibernate-orm · error · SemanticException

Operand of 'by' is of type '" + nodeType.getTypeName() + "'

Error message

Operand of 'by' is of type '" + nodeType.getTypeName() + "' which is not a duration (its JDBC type code is not duration-like)

What it means

HQL's `by` operator converts a duration to a number in a unit (`(d.end - d.start) by day`). TypecheckUtil.assertDuration (called from SemanticQueryBuilder:3800 while parsing `by`) requires the operand's JDBC type to be duration-like; applying `by` to a datetime, number, or string throws this SemanticException.

Source

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

	public static void assertString(SqmExpression<?> expression) {
		final var nodeType = expression.getNodeType();
		if ( nodeType != null ) {
			if ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )
					|| !jdbcMapping.getJdbcType().isStringLike() ) {
				throw new SemanticException(
						"Operand of 'like' is of type '" + nodeType.getTypeName() +
								"' which is not a string (its JDBC type code is not string-like)"
				);
			}
		}
	}

	public static void assertDuration(SqmExpression<?> expression) {
		final var nodeType = expression.getNodeType();
		if ( nodeType != null ) {
			if ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )
					|| !jdbcMapping.getJdbcType().isDuration() ) {
				throw new SemanticException(
						"Operand of 'by' is of type '" + nodeType.getTypeName() +
								"' which is not a duration (its JDBC type code is not duration-like)"
				);
			}
		}
	}

	public static void assertNumeric(SqmExpression<?> expression, UnaryArithmeticOperator op) {
		final var nodeType = expression.getExpressible();
		if ( nodeType != null ) {
			if ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )
					|| !jdbcMapping.getJdbcType().isNumber() ) {
				throw new SemanticException(
						"Operand of " + op.getOperatorChar() + " is of type '" + nodeType.getTypeName() +
								"' which is not a numeric type (its JDBC type code is not numeric)"
				);
			}
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. For datetime fields use `extract(day from e.eventDate)`
  2. Compute the duration first, then convert: `(e.endDate - e.startDate) by day`
  3. Check the operand attribute is a java.time.Duration/Period before using `by`

Example fix

// before
select e.eventDate by day from Event e

// after
select extract(day from e.eventDate) from Event e
Defensive patterns

Strategy: try-catch

Validate before calling

// Choose the right conversion based on operand type
Class<?> t = mm.entity(Event.class).getSingularAttribute("span").getJavaType();
String expr = java.time.temporal.TemporalAmount.class.isAssignableFrom(t)
    ? "e.span by day"
    : "extract(day from e.eventDate)"; // never apply 'by' to a datetime

Type guard

static boolean isDuration(Class<?> c) {
    return java.time.temporal.TemporalAmount.class.isAssignableFrom(c);
}

Try / catch

try {
    return em.createQuery(hql, Long.class).getSingleResult();
} catch (org.hibernate.query.SemanticException e) {
    throw new QueryBuildException("'by' needs a duration — use extract() for datetimes: " + hql, e);
}

Prevention

When it happens

Trigger: `e.eventDate by day` (a datetime, not a duration); `5 by day`; `e.someLong by hour`; forgetting to first compute a difference — `by` only accepts the duration that date subtraction produces.

Common situations: Confusing `x by unit` (duration → number) with `extract(field from x)` (datetime → number); porting PostgreSQL `EXTRACT(EPOCH FROM ...)` patterns; new duration support in Hibernate 6.2+ used with the wrong operand.

Related errors


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