{"record":{"id":"a3bf36a6b68ffcc9","repo":"hibernate/hibernate-orm","slug":"function-has-function-kind-but-other-overloads","errorCode":null,"errorMessage":"Function has function kind {}, but other overloads have {}. An overloaded function needs a single function kind.","messagePattern":"Function has function kind (.+?), but other overloads have (.+?)\\. An overloaded function needs a single function kind\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/dialect/function/DynamicDispatchFunction.java","lineNumber":51,"sourceCode":"\tpublic DynamicDispatchFunction(SqmFunctionRegistry functionRegistry, String... functionNames) {\n\t\tthis.functionRegistry = functionRegistry;\n\t\tthis.functionNames = functionNames;\n\t\tthis.functionKind = functionKind( functionRegistry, functionNames );\n\t}\n\n\tprivate static FunctionKind functionKind(SqmFunctionRegistry functionRegistry, String[] functionNames) {\n\t\tFunctionKind functionKind = null;\n\t\t// Sanity check\n\t\tfor ( String overload : functionNames ) {\n\t\t\tfinal var functionDescriptor = functionRegistry.findFunctionDescriptor( overload );\n\t\t\tif ( functionDescriptor == null ) {\n\t\t\t\tthrow new IllegalArgumentException( \"No function registered under the name '\" + overload + \"'\" );\n\t\t\t}\n\t\t\tif ( functionKind == null ) {\n\t\t\t\tfunctionKind = functionDescriptor.getFunctionKind();\n\t\t\t}\n\t\t\telse if ( functionKind != functionDescriptor.getFunctionKind() ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Function has function kind \" + functionDescriptor.getFunctionKind()\n\t\t\t\t\t\t\t\t\t\t\t\t\t+ \", but other overloads have \" + functionKind\n\t\t\t\t\t\t\t\t\t\t\t\t\t+ \". An overloaded function needs a single function kind.\" );\n\t\t\t}\n\t\t}\n\t\treturn functionKind;\n\t}\n\n\t@Override\n\tpublic FunctionKind getFunctionKind() {\n\t\treturn functionKind;\n\t}\n\n\t@Override\n\tpublic <T> SelfRenderingSqmFunction<T> generateSqmExpression(\n\t\t\tList<? extends SqmTypedNode<?>> arguments,\n\t\t\tReturnableType<T> impliedResultType,\n\t\t\tQueryEngine queryEngine) {\n\t\treturn validateGetFunction( arguments, queryEngine )","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/dialect/function/DynamicDispatchFunction.java#L33-L69","documentation":"DynamicDispatchFunction requires all overloads of a name to share one FunctionKind (NORMAL, ORDER_BY, AGGREGATE, WINDOW). The constructor compares each overload's getFunctionKind() with the first one seen and throws when they differ, because the SQM -> SQL translator would otherwise not know how to legally place the function in the query.","triggerScenarios":"Grouping incompatible descriptors under one dispatch name, e.g. an aggregate descriptor (cast function used with OVER/aggregate semantics) plus a normal SQM function, then registering a DynamicDispatchFunction over both names; happens in custom dialect setup or programmatic registry tweaks.","commonSituations":"Dialect authors adding an overload that is an aggregate/window variant but forgetting it must be registered under a different name; refactoring function descriptors so a kind changed (e.g. making a function order-by-only) while the dispatch group was not updated.","solutions":["Split the overloads by kind: register aggregate/window variants under distinct function names and only group same-kind descriptors in DynamicDispatchFunction","Check getFunctionKind() of each descriptor you pass; keep FunctionKind uniform across the group","Upgrade intent: if you need mixed kinds, implement a custom SqmFunctionDescriptor whose generateSqmExpression dispatches per-call instead of relying on DynamicDispatchFunction"],"exampleFix":"// before: kinds differ -> IllegalArgumentException at bootstrap\nnew DynamicDispatchFunction(registry, \"myagg_normal\", \"myagg_aggregate\");\n\n// after: same-kind dispatch; aggregate registered separately\nnew DynamicDispatchFunction(registry, \"myagg_int\", \"myagg_str\");\nregistry.registerFunction(\"myagg\", myAggregateDescriptor);","handlingStrategy":"validation","validationCode":"FunctionKind kind = descriptors[0].getFunctionKind();\nfor (SqmFunctionDescriptor d : descriptors) {\n    if (d.getFunctionKind() != kind) {\n        throw new IllegalStateException(\"Mixed FunctionKinds in overload group\");\n    }\n}","typeGuard":"boolean sameKind(SqmFunctionDescriptor... ds) {\n    FunctionKind k = ds[0].getFunctionKind();\n    return Arrays.stream(ds).allMatch(d -> d.getFunctionKind() == k);\n}","tryCatchPattern":null,"preventionTips":["Group overloads by FunctionKind; keep aggregate/window variants under their own dispatch names","Review FunctionKind whenever a descriptor is refactored","Assert kind uniformity in dialect unit tests"],"tags":["hibernate","function-registry","overloading","function-kind","custom-dialect"],"backgroundTag":"function-not-registered","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}