{"record":{"id":"7958816c0a146804","repo":"hibernate/hibernate-orm","slug":"couldn-t-determine-types-of-arguments-to-function","errorCode":null,"errorMessage":"Couldn't determine types of arguments to function 'generate_series'","messagePattern":"Couldn't determine types of arguments to function 'generate_series'","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/GenerateSeriesSetReturningFunctionTypeResolver.java","lineNumber":54,"sourceCode":"\tprotected final String defaultIndexSelectionExpression;\n\n\tpublic GenerateSeriesSetReturningFunctionTypeResolver(@Nullable String defaultValueColumnName, String defaultIndexSelectionExpression) {\n\t\tthis.defaultValueColumnName = defaultValueColumnName;\n\t\tthis.defaultIndexSelectionExpression = defaultIndexSelectionExpression;\n\t}\n\n\t@Override\n\tpublic AnonymousTupleType<?> resolveTupleType(List<? extends SqmTypedNode<?>> arguments, TypeConfiguration typeConfiguration) {\n\t\tfinal SqmTypedNode<?> start = arguments.get( 0 );\n\t\tfinal SqmTypedNode<?> stop = arguments.get( 1 );\n\t\tfinal SqmExpressible<?> startExpressible = start.getExpressible();\n\t\tfinal SqmExpressible<?> stopExpressible = stop.getExpressible();\n\t\tfinal SqmDomainType<?> type = NullnessHelper.coalesce(\n\t\t\t\tstartExpressible == null ? null : startExpressible.getSqmType(),\n\t\t\t\tstopExpressible == null ? null : stopExpressible.getSqmType()\n\t\t);\n\t\tif ( type == null ) {\n\t\t\tthrow new IllegalArgumentException( \"Couldn't determine types of arguments to function 'generate_series'\" );\n\t\t}\n\n\t\tfinal SqmBindableType<?>[] componentTypes = new SqmBindableType<?>[]{ type, typeConfiguration.getBasicTypeForJavaType( Long.class ) };\n\t\tfinal String[] componentNames = new String[]{ CollectionPart.Nature.ELEMENT.getName(), CollectionPart.Nature.INDEX.getName() };\n\t\treturn new AnonymousTupleType<>( componentTypes, componentNames );\n\t}\n\n\t@Override\n\tpublic SelectableMapping[] resolveFunctionReturnType(\n\t\t\tList<? extends SqlAstNode> arguments,\n\t\t\tString tableIdentifierVariable,\n\t\t\tboolean lateral,\n\t\t\tboolean withOrdinality,\n\t\t\tSqmToSqlAstConverter converter) {\n\t\tfinal Expression start = (Expression) arguments.get( 0 );\n\t\tfinal Expression stop = (Expression) arguments.get( 0 );\n\t\tfinal JdbcMappingContainer expressionType = NullnessHelper.coalesce(\n\t\t\t\tstart.getExpressionType(),","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/GenerateSeriesSetReturningFunctionTypeResolver.java#L36-L72","documentation":"Hibernate's set-returning function support (6.5+/7.x) builds an AnonymousTupleType for generate_series from the SQM types of the start and stop arguments. resolveTupleType coalesces the two arguments' expressible types; if both come back null (no type information on either argument) the tuple type cannot be constructed and the query fails during interpretation with this IllegalArgumentException.","triggerScenarios":"HQL/criteria generate_series calls where neither bound argument carries a resolvable SQM type: generate_series(:start, :stop) with parameters registered as Object/untyped, null literals passed as bounds, or arithmetic over untyped parameters.","commonSituations":"Porting native PostgreSQL generate_series queries to HQL; dynamic query builders that bind parameters without an explicit type class; null-valued bounds during exploratory testing; older 6.x releases with weaker type inference for set-returning functions.","solutions":["Give the parameters an explicit type at bind time: q.setParameter(\"start\", 1, Integer.class), or cast in HQL: generate_series(cast(:start as integer), cast(:stop as integer))","Use typed literals or cb.literal(...) in criteria queries instead of raw parameters","Bind non-null numeric defaults instead of null bounds","Upgrade to the latest 6.x/7.x patch release — generate_series type inference improved across versions"],"exampleFix":"// before\nem.createQuery(\"select s from generate_series(:a, :b) s(serie, idx)\", Object[].class)\n  .setParameter(\"a\", from)   // untyped Object binding\n  .setParameter(\"b\", to);\n\n// after\nem.createQuery(\"select s from generate_series(cast(:a as integer), cast(:b as integer)) s(serie, idx)\", Object[].class)\n  .setParameter(\"a\", from)\n  .setParameter(\"b\", to);","handlingStrategy":"validation","validationCode":"// Fail fast before query creation: series bounds must be non-null, concretely typed numbers\nstatic void checkSeriesBounds(Object start, Object stop) {\n    if (!(start instanceof Number) || !(stop instanceof Number)) {\n        throw new IllegalArgumentException(\n            \"generate_series bounds must be non-null Numbers, got: \" + start + \", \" + stop);\n    }\n}","typeGuard":"static boolean isTypedSeriesBound(Object v) {\n    return v instanceof Integer || v instanceof Long\n        || v instanceof java.math.BigInteger || v instanceof java.math.BigDecimal;\n}","tryCatchPattern":"try {\n    return em.createQuery(hql, Object[].class).getResultList();\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"generate_series\")) {\n        throw new QuerySetupException(\"generate_series arguments need explicit types; use cast(:a as integer)\", e);\n    }\n    throw e;\n}","preventionTips":["Always bind parameters with an explicit type class (setParameter(name, value, Integer.class))","Prefer cast(:param as <type>) for function arguments in HQL","Smoke-test dynamic HQL at startup with representative bindings"],"tags":["hibernate","hql","generate-series","type-inference","query-parameters"],"backgroundTag":"untyped-query-parameter","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}