theonedev/onedev · error · ValidationException

Parameter types do not match: expected type {expected} but f

Error message

Parameter types do not match: expected type {expected} but found {actual} for parameter index {index} of {executable}.

What it means

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.

Source

Thrown at server-core/src/main/java/org/hibernate/validator/internal/engine/ValidatorImpl.java:1036

		ValueContext<T, Object> valueContext = getExecutableValueContext(
				validationContext.getRootBean(), executableMetaData, executableMetaData.getValidatableParametersMetaData(), currentValidatedGroup
		);

		// 2. validate parameter constraints
		for ( int i = 0; i < parameterValues.length; i++ ) {
			ParameterMetaData parameterMetaData = executableMetaData.getParameterMetaData( i );
			Object value = parameterValues[i];

			if ( value != null ) {
				Class<?> valueType = value.getClass();
				if ( parameterMetaData.getType() instanceof Class && ( (Class<?>) parameterMetaData.getType() ).isPrimitive() ) {
					valueType = ReflectionHelper.unBoxedType( valueType );
				}
				if ( !TypeHelper.isAssignable(
						TypeHelper.getErasedType( parameterMetaData.getType() ),
						valueType
				) ) {
					throw LOG.getParameterTypesDoNotMatchException(
							valueType,
							parameterMetaData.getType(),
							i,
							validationContext.getExecutable()
					);
				}
			}

			validateMetaConstraints( validationContext, valueContext, parameterValues, parameterMetaData );
			if ( shouldFailFast( validationContext ) ) {
				return;
			}
		}
	}

	private <T> ValueContext<T, Object> getExecutableValueContext(T object, ExecutableMetaData executableMetaData, Validatable validatable, Class<?> group) {
		ValueContext<T, Object> valueContext;

View on GitHub (pinned to d44925c47c)

Solutions

  1. Ensure each supplied value matches the declared parameter type at the matching index (convert/coerce before calling validateParameters).
  2. Verify the parameter order — a transposition often causes index/type mismatch.
  3. For primitive parameters pass the boxed wrapper (Integer for int); the validator unboxes it, but a wrong wrapper (Long for int) is rejected.
  4. Use the executable's actual parameter types (getParameterTypes()) instead of assumed types when building the array.

Example fix

// before
Object[] args = { String.valueOf(userId) }; // userId param is Long
validator.forExecutables().validateParameters(service, method, args);

// after
Object[] args = { Long.valueOf(userId) };
validator.forExecutables().validateParameters(service, method, args);
Defensive patterns

Strategy: validation

Validate before calling

for (int i = 0; i < args.length; i++) {
    Class<?> p = method.getParameterTypes()[i];
    Object v = args[i];
    boolean ok = v == null || p.isInstance(v)
        || (p.isPrimitive() && isBoxCompatible(p, v.getClass()));
    if (!ok) throw new IllegalArgumentException(
        "arg " + i + " type " + v.getClass() + " not assignable to " + p);
}

Type guard

static boolean matchesParam(Object value, Class<?> paramType) {
    if (value == null) return !paramType.isPrimitive();
    Class<?> boxed = paramType.isPrimitive()
        ? MethodHandles.lookup().findConstructor(
              boxFor(paramType), methodType(void.class, paramType)) != null
            ? boxFor(paramType) : Object.class
        : paramType;
    return boxed.isInstance(value);
}

Try / catch

try {
    validator.forExecutables().validateParameters(target, method, args);
} catch (ValidationException e) {
    if (e.getMessage().startsWith("Parameter types do not match")) {
        // coerce arg types per method.getGenericParameterTypes() and retry
    } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: Building argument arrays reflectively (from request maps, JSON, or framework dispatchers), refactoring parameter types without updating callers, autoboxing assumptions with primitive parameters.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/e93bf281fa6e8a0b. Report an issue: GitHub.