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
- Pass an editable class that the target actually implements/extends (commonly target.getClass() or a shared interface of target).
- If you do not need filtering, call copyProperties(source, target) without the editable argument.
- For proxies, pass the user class / interface rather than the synthetic proxy class, or unwrap the proxy first.
- 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
- Pass an editable class the target implements/extends (or omit it).
- Mind argument order: copyProperties(source, target, editable) — editable applies to target.
- Unwrap proxies before copying, or pass the user interface as editable.
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
- Could not copy property '${targetPd.getName()}' from source
- Specified class is an interface
- Is it an abstract class?
- Is the constructor accessible?
- No default constructor found
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/3198d339ab3bea2a.json.
Report an issue: GitHub.