{"record":{"id":"898018cd556bd793","repo":"hibernate/hibernate-orm","slug":"cannot-mix-positional-parameter-with-named-paramet","errorCode":null,"errorMessage":"Cannot mix positional parameter with named parameter registrations","messagePattern":"Cannot mix positional parameter with named parameter registrations","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java","lineNumber":50,"sourceCode":" * expandable parameter registrations\n *\n * @author Steve Ebersole\n */\nclass ProcedureParameterMetadataImpl implements ProcedureParameterMetadataImplementor {\n\tprivate ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;\n\tprivate List<ProcedureParameterImplementor<?>> parameters;\n\n\t@Override\n\tpublic void registerParameter(ProcedureParameterImplementor<?> parameter) {\n\t\tif ( parameter.isNamed() ) {\n\t\t\tif ( parameterStrategy == ParameterStrategy.POSITIONAL ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Cannot mix named parameter with positional parameter registrations\" );\n\t\t\t}\n\t\t\tparameterStrategy = ParameterStrategy.NAMED;\n\t\t}\n\t\telse if ( parameter.isOrdinal() ) {\n\t\t\tif ( parameterStrategy == ParameterStrategy.NAMED ) {\n\t\t\t\tthrow new IllegalArgumentException( \"Cannot mix positional parameter with named parameter registrations\" );\n\t\t\t}\n\t\t\tparameterStrategy = ParameterStrategy.POSITIONAL;\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException( \"Unrecognized parameter type : \" + parameter );\n\t\t}\n\t\tif ( parameters == null ) {\n\t\t\tparameters = new ArrayList<>();\n\t\t}\n\t\tparameters.add( parameter );\n\t}\n\n\t@Override\n\tpublic QueryParameterBindings createBindings(SessionFactoryImplementor sessionFactory) {\n\t\treturn QueryParameterBindingsImpl.from( this, sessionFactory );\n\t}\n\n\t@Override","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/procedure/internal/ProcedureParameterMetadataImpl.java#L32-L68","documentation":"Mirror of the named-after-positional check: registerParameter throws IllegalArgumentException 'Cannot mix positional parameter with named parameter registrations' when an ordinal registration follows an existing named registration. Hibernate stores one ParameterStrategy per call and rejects the second style as soon as it detects the conflict.","triggerScenarios":"call.registerParameter(\"mode\", String.class, ParameterMode.IN) followed by call.registerParameter(2, Integer.class, ParameterMode.IN) on the same ProcedureCall; same pattern through Jakarta registerStoredProcedureParameter.","commonSituations":"Refactoring named registrations to positional (or vice versa) but leaving one call site behind; wrapper code auto-appending an extra positional parameter (e.g., a tenant or audit parameter) to a call that used named parameters.","solutions":["Convert the remaining registration to the style already in use for that call","Search all call sites of the procedure for registerParameter/registerStoredProcedureParameter and align styles","Centralize registration in one helper that takes the style once so mixing is structurally impossible"],"exampleFix":"// before\ncall.registerParameter(\"orderId\", Long.class, ParameterMode.IN);\ncall.registerParameter(2, String.class, ParameterMode.IN); // mixing!\n\n// after\ncall.registerParameter(\"orderId\", Long.class, ParameterMode.IN);\ncall.registerParameter(\"comment\", String.class, ParameterMode.IN);","handlingStrategy":"validation","validationCode":"// Guard before registering the second style\nif (call.getParameterMetadata() != null && !call.getParameterMetadata().hasNamedParameters()\n        && call.getParameterMetadata().hasPositionalParameters()) {\n    // call already positional: register positionally\n}","typeGuard":null,"tryCatchPattern":"try {\n    call.registerParameter(2, Integer.class, ParameterMode.IN);\n} catch (IllegalArgumentException e) {\n    // call already uses named parameters: switch to the named overload\n}","preventionTips":["Pick one registration style per ProcedureCall and stick to it","Keep wrapper/framework code from appending parameters of the opposite style","Cover each procedure call with an integration test that registers and binds all parameters"],"tags":["hibernate","stored-procedure","parameter-binding","api-misuse"],"backgroundTag":"mixed-named-positional-parameters","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}