{"record":{"id":"5a589c160cdbde6e","repo":"hibernate/hibernate-orm","slug":"tuple-constructor-must-have-at-least-one-element","errorCode":null,"errorMessage":"Tuple constructor must have at least one element","messagePattern":"Tuple constructor must have at least one element","errorType":"exception","errorClass":"SemanticException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmTuple.java","lineNumber":54,"sourceCode":"\t\timplements JpaCompoundSelection<T> {\n\tprivate final List<SqmExpression<?>> groupedExpressions;\n\n\tpublic SqmTuple(NodeBuilder nodeBuilder, SqmExpression<?>... groupedExpressions) {\n\t\tthis( Arrays.asList( groupedExpressions ), nodeBuilder );\n\t}\n\n\tpublic SqmTuple(NodeBuilder nodeBuilder, SqmBindableType<T> type, SqmExpression<?>... groupedExpressions) {\n\t\tthis( Arrays.asList( groupedExpressions ), type, nodeBuilder );\n\t}\n\n\tpublic SqmTuple(List<SqmExpression<?>> groupedExpressions, NodeBuilder nodeBuilder) {\n\t\tthis( groupedExpressions, null, nodeBuilder );\n\t}\n\n\tpublic SqmTuple(List<SqmExpression<?>> groupedExpressions, @Nullable SqmBindableType<T> type, NodeBuilder nodeBuilder) {\n\t\tsuper( type, nodeBuilder );\n\t\tif ( groupedExpressions.isEmpty() ) {\n\t\t\tthrow new SemanticException( \"Tuple constructor must have at least one element\" );\n\t\t}\n\t\tthis.groupedExpressions = groupedExpressions;\n\t\tif ( type == null ) {\n\t\t\tsetExpressibleType( nodeBuilder.getTypeConfiguration().resolveTupleType( groupedExpressions ) );\n\t\t}\n\t}\n\n\t@Override\n\tpublic SqmTuple<T> copy(SqmCopyContext context) {\n\t\tfinal var existing = context.getCopy( this );\n\t\tif ( existing != null ) {\n\t\t\treturn existing;\n\t\t}\n\t\tfinal List<SqmExpression<?>> groupedExpressions = new ArrayList<>( this.groupedExpressions.size() );\n\t\tfor ( SqmExpression<?> groupedExpression : this.groupedExpressions ) {\n\t\t\tgroupedExpressions.add( groupedExpression.copy( context ) );\n\t\t}\n\t\tfinal SqmTuple<T> expression = context.registerCopy(","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/expression/SqmTuple.java#L36-L72","documentation":"SqmTuple groups several expressions into one tuple-typed expression (used by in-tuples, multiselect, compound selections). A tuple with zero expressions has no component types to resolve (resolveTupleType) and cannot be rendered, so the constructor throws SemanticException('Tuple constructor must have at least one element').","triggerScenarios":"Creating an SqmTuple or builder.tuple with an empty list: cq.multiselect(new ArrayList<>()), builder.tuple(Collections.emptyList()), or building an IN-tuple predicate from a dynamically generated list of value combinations that turned out empty.","commonSituations":"Dynamic query construction where selections or IN values come from user input, configuration, or a loop that can yield zero items; empty multiselect lists after filtering; criteria helpers that wrap arbitrary lists in tuples.","solutions":["Guard the empty case: skip the query, return early, or substitute a default selection (e.g. the root id or a literal).","For dynamic IN lists, check emptiness before building the predicate and choose explicit semantics (match-nothing vs. skip filter).","Validate at the API boundary that callers supply at least one selection."],"exampleFix":"// before\nList<Selection<?>> sels = buildSelections( filter ); // may be empty\ncq.multiselect( sels );                              // SemanticException\n\n// after\nif ( sels.isEmpty() ) {\n    cq.multiselect( root.get( \"id\" ) ); // or throw a meaningful domain exception\n} else {\n    cq.multiselect( sels );\n}","handlingStrategy":"validation","validationCode":"if ( selections == null || selections.isEmpty() ) {\n    throw new IllegalArgumentException( \"multiselect/tuple requires at least one selection\" );\n}\ncq.multiselect( selections );","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check selection lists for emptiness before calling multiselect()/tuple().","For dynamic IN lists, decide explicit empty-list semantics (skip filter vs. match nothing) up front.","Validate at the API boundary that callers supply at least one selection."],"tags":["hibernate","sqm","tuple","multiselect","empty-list","criteria-api"],"backgroundTag":"empty-selection-list","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}