{"record":{"id":"6593ba03c94c2025","repo":"hibernate/hibernate-orm","slug":"no-assignments-specified-as-part-of-update-criteri","errorCode":null,"errorMessage":"No assignments specified as part of UPDATE criteria","messagePattern":"No assignments specified as part of UPDATE criteria","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/update/SqmUpdateStatement.java","lineNumber":156,"sourceCode":"\t\t\t\tnew SqmUpdateStatement<>(\n\t\t\t\t\t\tnodeBuilder(),\n\t\t\t\t\t\tnewQuerySource == null ? getQuerySource() : newQuerySource,\n\t\t\t\t\t\tcopyParameters( context ),\n\t\t\t\t\t\tcopyCteStatements( context ),\n\t\t\t\t\t\tgetTarget().copy( context ),\n\t\t\t\t\t\tversioned\n\t\t\t\t)\n\t\t);\n\t\tstatement.setWhereClause( copyWhereClause( context ) );\n\t\tstatement.setClause = setClause.copy( context );\n\t\treturn statement;\n\t}\n\n\t@Override\n\tpublic void validate(@Nullable String hql) {\n\t\tverifyImmutableEntityUpdate( hql );\n\t\tif ( getSetClause().getAssignments().isEmpty() ) {\n\t\t\tthrow new IllegalArgumentException( \"No assignments specified as part of UPDATE criteria\" );\n\t\t}\n\t\tif ( getQuerySource() == SqmQuerySource.CRITERIA ) {\n\t\t\tSqmUtil.validateCriteriaTree( this );\n\t\t}\n\t\tverifyUpdateTypesMatch();\n\t}\n\n\tprivate void verifyImmutableEntityUpdate(@Nullable String hql) {\n\t\tfinal EntityPersister persister =\n\t\t\t\tnodeBuilder().getMappingMetamodel().getEntityDescriptor( getTarget().getEntityName() );\n\t\tif ( !persister.isMutable() ) {\n\t\t\tfinal String querySpaces = Arrays.toString( persister.getQuerySpaces() );\n\t\t\tswitch ( nodeBuilder().getImmutableEntityUpdateQueryHandlingMode() ) {\n\t\t\t\tcase ALLOW :\n\t\t\t\t\tCORE_LOGGER.immutableEntityUpdateQueryAllowed( hql, querySpaces );\n\t\t\t\t\tbreak;\n\t\t\t\tcase WARNING:\n\t\t\t\t\tCORE_LOGGER.immutableEntityUpdateQuery( hql, querySpaces );","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/update/SqmUpdateStatement.java#L138-L174","documentation":"Before an UPDATE statement is executed, SqmUpdateStatement.validate() checks the SET clause contains at least one assignment. A criteria update built with cb.createCriteriaUpdate(...) but without any set(...) call has nothing to update, and Hibernate throws IllegalArgumentException. HQL updates always carry assignments syntactically, so this error is essentially criteria-only.","triggerScenarios":"CriteriaUpdate<T> update = cb.createCriteriaUpdate(T.class); update.where(...); em.createQuery(update).executeUpdate() — with no update.set(attribute, value) call, typically because a dynamic builder's set-list came out empty.","commonSituations":"Dynamically composed updates whose assignments are driven by a diff/patch map that is empty (nothing changed); refactors that move set() calls behind a condition; copy-pasted update templates missing the set line.","solutions":["Add at least one set(...) before creating/executing the query — verify update.getSetClause()/assignments are non-empty if you keep a reference to the Hibernate API","In dynamic builders, skip execution entirely when no assignments were produced (an empty update is usually a no-op anyway)","Fail fast with your own validation right after building, so the message points at your code rather than Hibernate internals"],"exampleFix":"// before\nCriteriaUpdate<User> u = cb.createCriteriaUpdate(User.class);\nRoot<User> root = u.from(User.class);\nu.where(cb.equal(root.get(\"id\"), userId));\n// no u.set(...) — nothing to update\nem.createQuery(u).executeUpdate(); // IllegalArgumentException\n\n// after\nif (changes.isEmpty()) { return; } // nothing changed, skip\nchanges.forEach((attr, val) -> u.set(root.get(attr), val));\nem.createQuery(u).executeUpdate();","handlingStrategy":"validation","validationCode":"if (changes.isEmpty()) { return 0; } // nothing to update — skip before building\nCriteriaUpdate<T> u = cb.createCriteriaUpdate(entity);\nchanges.forEach((attr, val) -> u.set(root.get(attr), val));","typeGuard":null,"tryCatchPattern":"try { return em.createQuery(update).executeUpdate(); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"No assignments\")) { return 0; } else throw e; }","preventionTips":["Treat an empty diff as a no-op and never build the update statement","Assert update has at least one set() in a helper right before execution","Write a test for the 'nothing changed' path of every dynamic update builder"],"tags":["hibernate","criteria-api","bulk-update","validation"],"backgroundTag":"criteria-update-missing-set","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}