{"record":{"id":"4fa4fb0402aa19bd","repo":"hibernate/hibernate-orm","slug":"cannot-assign-expression-of-type-s-to-target-pa","errorCode":null,"errorMessage":"Cannot assign expression of type '%s' to target path '%s' of type '%s'","messagePattern":"Cannot assign expression of type '(.+?)' to target path '(.+?)' of type '(.+?)'","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java","lineNumber":490,"sourceCode":"\t\tif ( expression instanceof SqmLiteralNull ) {\n\t\t\t// TODO: check that the target path is nullable\n\t\t}\n\t\telse {\n\t\t\tfinal var targetType = targetPath.getNodeType();\n\t\t\tfinal var expressionType = expression.getNodeType();\n\t\t\tif ( targetType != null && expressionType != null && targetPath.isEnum() ) {\n\t\t\t\t// this is needed by Hibernate Processor due to the weird\n\t\t\t\t// handling of enumerated types in the annotation processor\n\t\t\t\tif ( !Objects.equals( targetType.getTypeName(), expressionType.getTypeName() ) ) {\n\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\"Cannot compare left expression of enumerated type '%s' with right expression of enumerated type '%s'\",\n\t\t\t\t\t\t\ttargetType.getTypeName(),\n\t\t\t\t\t\t\texpressionType.getTypeName()\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if ( !isTypeAssignable( targetType, expressionType, bindingContext) ) {\n\t\t\t\tthrow new SemanticException(\n\t\t\t\t\t\tString.format(\n\t\t\t\t\t\t\t\t\"Cannot assign expression of type '%s' to target path '%s' of type '%s'\",\n\t\t\t\t\t\t\t\texpressionType.getTypeName(),\n\t\t\t\t\t\t\t\ttargetPath.toHqlString(),\n\t\t\t\t\t\t\t\ttargetType.getTypeName()\n\t\t\t\t\t\t),\n\t\t\t\t\t\thqlString,\n\t\t\t\t\t\tnull\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic static void assertOperable(SqmExpression<?> left, SqmExpression<?> right, BinaryArithmeticOperator op) {\n\t\tfinal var leftNodeType = left.getExpressible();\n\t\tfinal var rightNodeType = right.getExpressible();\n\t\tif ( leftNodeType != null && rightNodeType != null ) {\n\t\t\tfinal var leftJavaType = leftNodeType.getRelationalJavaType().getJavaTypeClass();","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/internal/TypecheckUtil.java#L472-L508","documentation":"Thrown as SemanticException by TypecheckUtil.assertAssignable when an expression being assigned to a target path has a type that is not assignable to the path's type. This guards assignment positions — primarily the SET clause of HQL UPDATE statements and criteria update cb.set(path, value) — so 'update Person p set p.age = ...' rejects an expression whose type cannot become the attribute's type (String into int, wrong enum, entity into scalar).","triggerScenarios":"HQL 'update Person p set p.age = \"42\"' (string expression into numeric attribute); 'set p.status = \"ACTIVE\"' where status is an enum compared against a plain string; criteria update cb.set(root.get(\"age\"), someString); dynamic update builders copying values from a DTO/map with stringified numbers into typed attributes.","commonSituations":"Bulk update endpoints accepting JSON where all values arrive as strings; ETL/import scripts doing string-based updates; copy-pasting SET clauses between entities with different attribute types; refactoring an attribute's type without updating bulk update statements.","solutions":["Convert the value to the attribute's type before binding: setParameter(\"age\", 42, Integer.class)","Cast inside HQL when necessary: set p.age = cast(:v as int)","Fix the update statement to use a correctly typed expression (numeric literal, enum literal)","For criteria updates, use the typed set(Path<Y>, Y) overload so the compiler checks the value type"],"exampleFix":"// before\nint n = session.createMutationQuery(\"update Person p set p.age = :age\")\n        .setParameter(\"age\", \"42\") // String into int attribute\n        .executeUpdate();\n// after\nint n = session.createMutationQuery(\"update Person p set p.age = :age\")\n        .setParameter(\"age\", 42, Integer.class)\n        .executeUpdate();","handlingStrategy":"validation","validationCode":"static Object checkAssignable(ManagedType<?> type, String attr, Object value) {\n    Class<?> javaType = ((SingularAttribute<?, ?>) type.getAttribute(attr)).getJavaType();\n    if (value != null && !javaType.isInstance(value)) {\n        throw new IllegalArgumentException(\n            \"Value \" + value + \" (\" + value.getClass().getSimpleName() + \") not assignable to \"\n                + attr + \" of type \" + javaType.getSimpleName());\n    }\n    return value;\n}\n// use before building the update: cb.set(root.get(attr), (Comparable) checkAssignable(type, attr, value));","typeGuard":"static <Y> Y guardSetType(Class<Y> attrType, Object value) {\n    if (value == null || attrType.isInstance(value)) {\n        return attrType.cast(value);\n    }\n    throw new IllegalArgumentException(\"Expected \" + attrType.getSimpleName() + \" but got \" + value.getClass().getSimpleName());\n}","tryCatchPattern":"try {\n    int n = session.createMutationQuery(\"update Person p set p.age = :age\")\n            .setParameter(\"age\", 42, Integer.class).executeUpdate();\n} catch (SemanticException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Cannot assign\")) {\n        throw new IllegalArgumentException(\"SET value type does not match attribute type\", e);\n    }\n    throw e;\n}","preventionTips":["Convert DTO/map input to the attribute's Java type before building the update","Use the typed set(Path<Y>, Y) criteria overload so the compiler enforces types","Keep bulk update statements next to the entity mapping so type changes get caught","Bind update parameters with explicit types: setParameter(name, value, Integer.class)"],"tags":["hibernate","hql","update-statement","type-mismatch","semantic-analysis"],"backgroundTag":"assignment-type-mismatch","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}