{"record":{"id":"e93bf281fa6e8a0b","repo":"theonedev/onedev","slug":"parameter-types-do-not-match-expected-type-expec","errorCode":null,"errorMessage":"Parameter types do not match: expected type {expected} but found {actual} for parameter index {index} of {executable}.","messagePattern":"Parameter types do not match: expected type (.+?) but found (.+?) for parameter index (.+?) of (.+?)\\.","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java","lineNumber":1036,"sourceCode":"\t\tValueContext<T, Object> valueContext = getExecutableValueContext(\n\t\t\t\tvalidationContext.getRootBean(), executableMetaData, executableMetaData.getValidatableParametersMetaData(), currentValidatedGroup\n\t\t);\n\n\t\t// 2. validate parameter constraints\n\t\tfor ( int i = 0; i < parameterValues.length; i++ ) {\n\t\t\tParameterMetaData parameterMetaData = executableMetaData.getParameterMetaData( i );\n\t\t\tObject value = parameterValues[i];\n\n\t\t\tif ( value != null ) {\n\t\t\t\tClass<?> valueType = value.getClass();\n\t\t\t\tif ( parameterMetaData.getType() instanceof Class && ( (Class<?>) parameterMetaData.getType() ).isPrimitive() ) {\n\t\t\t\t\tvalueType = ReflectionHelper.unBoxedType( valueType );\n\t\t\t\t}\n\t\t\t\tif ( !TypeHelper.isAssignable(\n\t\t\t\t\t\tTypeHelper.getErasedType( parameterMetaData.getType() ),\n\t\t\t\t\t\tvalueType\n\t\t\t\t) ) {\n\t\t\t\t\tthrow LOG.getParameterTypesDoNotMatchException(\n\t\t\t\t\t\t\tvalueType,\n\t\t\t\t\t\t\tparameterMetaData.getType(),\n\t\t\t\t\t\t\ti,\n\t\t\t\t\t\t\tvalidationContext.getExecutable()\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvalidateMetaConstraints( validationContext, valueContext, parameterValues, parameterMetaData );\n\t\t\tif ( shouldFailFast( validationContext ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate <T> ValueContext<T, Object> getExecutableValueContext(T object, ExecutableMetaData executableMetaData, Validatable validatable, Class<?> group) {\n\t\tValueContext<T, Object> valueContext;\n","sourceCodeStart":1018,"sourceCodeEnd":1054,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java#L1018-L1054","documentation":"Thrown during executable parameter validation when a supplied argument value's runtime type cannot be assigned to the declared parameter type (after considering unboxing of primitive wrappers). The validator rejects the invocation rather than validating values against constraints for incompatible types.","triggerScenarios":"validateParameters called with an Object[] where element i is not an instance of (or assignable to, incl. autoboxing) executableMetaData.getParameterTypes()[i] — e.g. passing a String where an Integer parameter is declared, or passing null-typed generics/wrapped values that lost their type at runtime.","commonSituations":"Building argument arrays reflectively (from request maps, JSON, or framework dispatchers), refactoring parameter types without updating callers, autoboxing assumptions with primitive parameters.","solutions":["Ensure each supplied value matches the declared parameter type at the matching index (convert/coerce before calling validateParameters).","Verify the parameter order — a transposition often causes index/type mismatch.","For primitive parameters pass the boxed wrapper (Integer for int); the validator unboxes it, but a wrong wrapper (Long for int) is rejected.","Use the executable's actual parameter types (getParameterTypes()) instead of assumed types when building the array."],"exampleFix":"// before\nObject[] args = { String.valueOf(userId) }; // userId param is Long\nvalidator.forExecutables().validateParameters(service, method, args);\n\n// after\nObject[] args = { Long.valueOf(userId) };\nvalidator.forExecutables().validateParameters(service, method, args);","handlingStrategy":"validation","validationCode":"for (int i = 0; i < args.length; i++) {\n    Class<?> p = method.getParameterTypes()[i];\n    Object v = args[i];\n    boolean ok = v == null || p.isInstance(v)\n        || (p.isPrimitive() && isBoxCompatible(p, v.getClass()));\n    if (!ok) throw new IllegalArgumentException(\n        \"arg \" + i + \" type \" + v.getClass() + \" not assignable to \" + p);\n}","typeGuard":"static boolean matchesParam(Object value, Class<?> paramType) {\n    if (value == null) return !paramType.isPrimitive();\n    Class<?> boxed = paramType.isPrimitive()\n        ? MethodHandles.lookup().findConstructor(\n              boxFor(paramType), methodType(void.class, paramType)) != null\n            ? boxFor(paramType) : Object.class\n        : paramType;\n    return boxed.isInstance(value);\n}","tryCatchPattern":"try {\n    validator.forExecutables().validateParameters(target, method, args);\n} catch (ValidationException e) {\n    if (e.getMessage().startsWith(\"Parameter types do not match\")) {\n        // coerce arg types per method.getGenericParameterTypes() and retry\n    } else throw e;\n}","preventionTips":["Build argument arrays using each declared parameter type (convert/coerce explicitly).","For primitives, pass the correct wrapper (Integer for int, not Long).","Beware boxing: Integer and Long are never interchangeable for primitive params."],"tags":["validation","type-mismatch","reflection","executable-validation"],"backgroundTag":"type-mismatch","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}