spring-projects/spring-framework · error · IntrospectionException

Type mismatch between read and write methods: ${readMethod}

Error message

Type mismatch between read and write methods: ${readMethod} - ${writeMethod}

What it means

IntrospectionException from PropertyDescriptorUtils.findPropertyType when the read method's return type and the write method's single parameter type are mutually non-assignable. The JavaBean contract requires the setter argument to be compatible with the getter return; if neither is assignable to the other, the descriptor has an inconsistent type and cannot be built.

Source

Thrown at spring-beans/src/main/java/org/springframework/beans/PropertyDescriptorUtils.java:177

				throw new IntrospectionException("Read method returns void: " + readMethod);
			}
		}

		if (writeMethod != null) {
			Class<?>[] params = writeMethod.getParameterTypes();
			if (params.length != 1) {
				throw new IntrospectionException("Bad write method arg count: " + writeMethod);
			}
			if (propertyType != null) {
				if (propertyType.isAssignableFrom(params[0])) {
					// Write method's property type potentially more specific
					propertyType = params[0];
				}
				else if (params[0].isAssignableFrom(propertyType)) {
					// Proceed with read method's property type
				}
				else {
					throw new IntrospectionException(
							"Type mismatch between read and write methods: " + readMethod + " - " + writeMethod);
				}
			}
			else {
				propertyType = params[0];
			}
		}

		return propertyType;
	}

	/**
	 * See {@link java.beans.IndexedPropertyDescriptor#findIndexedPropertyType}.
	 */
	public static @Nullable Class<?> findIndexedPropertyType(String name, @Nullable Class<?> propertyType,
			@Nullable Method indexedReadMethod, @Nullable Method indexedWriteMethod) throws IntrospectionException {

		Class<?> indexedPropertyType = null;

View on GitHub (pinned to e8729d0438)

Solutions

  1. Align getter return type and setter parameter type to the same property type.
  2. If a more specific setter is intended, ensure the setter param is assignable from the getter return.
  3. Regenerate Lombok-generated accessors and remove conflicting hand-written ones.

Example fix

// before
public Number getValue() { ... }
public void setValue(String v) { ... }  // String not assignable to/from Number

// after
public Number getValue() { ... }
public void setValue(Number v) { ... }
Defensive patterns

Strategy: type-guard

Validate before calling

static void assertReadWriteTypesMatch(Method readMethod, Method writeMethod) {
    Class<?> rt = readMethod.getReturnType();
    Class<?> wt = writeMethod.getParameterTypes()[0];
    if (!rt.isAssignableFrom(wt) && !wt.isAssignableFrom(rt)) {
        throw new IllegalStateException("Getter returns " + rt + " but setter takes " + wt);
    }
}

Type guard

static boolean accessorsTypeCompatible(Method readMethod, Method writeMethod) {
    Class<?> rt = readMethod.getReturnType();
    Class<?> wt = writeMethod.getParameterTypes()[0];
    return rt.isAssignableFrom(wt) || wt.isAssignableFrom(rt);
}

Try / catch

try {
    return new PropertyDescriptor(name, readMethod, writeMethod);
} catch (java.beans.IntrospectionException ex) {
    if (ex.getMessage().startsWith("Type mismatch between read and write")) {
        log.error("Fix accessor pair: getter returns {} setter takes {}",
            readMethod.getReturnType(), writeMethod.getParameterTypes()[0]);
    }
    throw ex;
}

Prevention

When it happens

Trigger: A property where getX() returns type A and setX(B) takes type B with A and B unrelated (neither isAssignableFrom the other). Surfaces during introspection of classes whose accessors were edited inconsistently.

Common situations: Refactor changed the getter return type but not the setter parameter (or vice versa); copy-paste of an accessor pattern with the wrong type; covariant return on getter not reflected in setter; Lombok @Accessors(fluent=true) plus a hand-written setter with a different type.

Related errors


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