spring-projects/spring-framework · error · IllegalArgumentException

Target class [${target.getClass().getName()}] not assignable

Error message

Target class [${target.getClass().getName()}] not assignable to editable class [${editable.getName()}]

What it means

Thrown as IllegalArgumentException by the private copyProperties(source, target, editable, ignoreProperties) when an 'editable' filter class is provided but the target object is not an instance of it (BeanUtils.java:803-807). The editable class is meant to restrict which properties are copied, and Spring asserts target assignability up front.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/BeanUtils.java:805

	 * when matching properties in the source and target objects. See the
	 * documentation for {@link #copyProperties(Object, Object)} for details.
	 * @param source the source bean
	 * @param target the target bean
	 * @param editable the class (or interface) to restrict property setting to
	 * @param ignoreProperties array of property names to ignore
	 * @throws BeansException if the copying failed
	 * @see BeanWrapper
	 */
	private static void copyProperties(Object source, Object target, @Nullable Class<?> editable,
			String @Nullable ... ignoreProperties) throws BeansException {

		Assert.notNull(source, "Source must not be null");
		Assert.notNull(target, "Target must not be null");

		Class<?> actualEditable = target.getClass();
		if (editable != null) {
			if (!editable.isInstance(target)) {
				throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
						"] not assignable to editable class [" + editable.getName() + "]");
			}
			actualEditable = editable;
		}
		PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
		Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null);
		CachedIntrospectionResults sourceResults = (actualEditable != source.getClass() ?
				CachedIntrospectionResults.forClass(source.getClass()) : null);

		for (PropertyDescriptor targetPd : targetPds) {
			Method writeMethod = targetPd.getWriteMethod();
			if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) {
				PropertyDescriptor sourcePd = (sourceResults != null ?
						sourceResults.getPropertyDescriptor(targetPd.getName()) : targetPd);
				if (sourcePd != null) {
					Method readMethod = sourcePd.getReadMethod();
					if (readMethod != null) {
						if (isAssignable(writeMethod, readMethod, sourcePd, targetPd)) {

View on GitHub (pinned to e8729d0438)

Solutions

  1. Pass an editable class that the target actually implements/extends (commonly target.getClass() or a shared interface of target).
  2. If you do not need filtering, call copyProperties(source, target) without the editable argument.
  3. For proxies, pass the user class / interface rather than the synthetic proxy class, or unwrap the proxy first.
  4. Double-check argument order: copyProperties(source, target, editable) — editable applies to target, not source.

Example fix

// before
BeanUtils.copyProperties(dto, entity, Dto.class); // entity not a Dto

// after
BeanUtils.copyProperties(dto, entity, Entity.class);
// or simply: BeanUtils.copyProperties(dto, entity);
Defensive patterns

Strategy: validation

Validate before calling

if (editable != null && !editable.isInstance(target)) {
  throw new IllegalArgumentException(
    "target " + target.getClass() + " not instance of editable " + editable);
}

Type guard

public static boolean editableMatches(Class<?> editable, Object target) {
  return editable == null || editable.isInstance(target);
}

Try / catch

try { BeanUtils.copyProperties(src, target, editable); }
catch (IllegalArgumentException e) {
  BeanUtils.copyProperties(src, target); // retry without the editable filter
}

Prevention

When it happens

Trigger: Calling BeanUtils.copyProperties(src, target, SomeClass.class) (or the variant with ignore-properties) where !SomeClass.class.isInstance(target). Exposed via BeanUtils.copyProperties(source, target, editable) and copyProperties(source, target, editable, ignoreProperties).

Common situations: Passing the source's class instead of the target's class as the editable filter; passing an interface the target does not implement; target being a proxy (CGLIB/JDK) whose runtime class differs; copying between unrelated DTOs while passing a third type as the filter.

Related errors


AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04). Data as JSON: /data/errors/3198d339ab3bea2a.json. Report an issue: GitHub.