{"record":{"id":"ab8db904bdf0061c","repo":"hibernate/hibernate-orm","slug":"operand-of-by-is-of-type-nodetype-gettypena","errorCode":null,"errorMessage":"Operand of 'by' is of type '\" + nodeType.getTypeName() + \"' which is not a duration (its JDBC type code is not duration-like)","messagePattern":"Operand of 'by' is of type '\" \\+ nodeType\\.getTypeName\\(\\) \\+ \"' which is not a duration \\(its JDBC type code is not duration-like\\)","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java","lineNumber":633,"sourceCode":"\tpublic static void assertString(SqmExpression<?> expression) {\n\t\tfinal var nodeType = expression.getNodeType();\n\t\tif ( nodeType != null ) {\n\t\t\tif ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )\n\t\t\t\t\t|| !jdbcMapping.getJdbcType().isStringLike() ) {\n\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\"Operand of 'like' is of type '\" + nodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\"' which is not a string (its JDBC type code is not string-like)\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void assertDuration(SqmExpression<?> expression) {\n\t\tfinal var nodeType = expression.getNodeType();\n\t\tif ( nodeType != null ) {\n\t\t\tif ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )\n\t\t\t\t\t|| !jdbcMapping.getJdbcType().isDuration() ) {\n\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\"Operand of 'by' is of type '\" + nodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\"' which is not a duration (its JDBC type code is not duration-like)\"\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void assertNumeric(SqmExpression<?> expression, UnaryArithmeticOperator op) {\n\t\tfinal var nodeType = expression.getExpressible();\n\t\tif ( nodeType != null ) {\n\t\t\tif ( !( nodeType.getSqmType() instanceof JdbcMapping jdbcMapping )\n\t\t\t\t\t|| !jdbcMapping.getJdbcType().isNumber() ) {\n\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\t\"Operand of \" + op.getOperatorChar() + \" is of type '\" + nodeType.getTypeName() +\n\t\t\t\t\t\t\t\t\"' which is not a numeric type (its JDBC type code is not numeric)\"\n\t\t\t\t);\n\t\t\t}\n\t\t}","sourceCodeStart":615,"sourceCodeEnd":651,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java#L615-L651","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["For datetime fields use `extract(day from e.eventDate)`","Compute the duration first, then convert: `(e.endDate - e.startDate) by day`","Check the operand attribute is a java.time.Duration/Period before using `by`"],"exampleFix":"// before\nselect e.eventDate by day from Event e\n\n// after\nselect extract(day from e.eventDate) from Event e","handlingStrategy":"try-catch","validationCode":"// Choose the right conversion based on operand type\nClass<?> t = mm.entity(Event.class).getSingularAttribute(\"span\").getJavaType();\nString expr = java.time.temporal.TemporalAmount.class.isAssignableFrom(t)\n    ? \"e.span by day\"\n    : \"extract(day from e.eventDate)\"; // never apply 'by' to a datetime","typeGuard":"static boolean isDuration(Class<?> c) {\n    return java.time.temporal.TemporalAmount.class.isAssignableFrom(c);\n}","tryCatchPattern":"try {\n    return em.createQuery(hql, Long.class).getSingleResult();\n} catch (org.hibernate.query.SemanticException e) {\n    throw new QueryBuildException(\"'by' needs a duration — use extract() for datetimes: \" + hql, e);\n}","preventionTips":["Rule of thumb: `by unit` converts durations; `extract(field from x)` reads datetimes","Compute the difference first: `(end - start) by day`","Double-check operand types when porting EXTRACT(EPOCH ...) SQL into HQL"],"tags":["hql","duration","extract","type-checking","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"}