spring-projects/spring-framework · error · IllegalArgumentException

Write method must have exactly 1 or 2 parameters

Error message

Write method must have exactly 1 or 2 parameters: {method}

What it means

Thrown as IllegalArgumentException by ExtendedBeanInfo when a non-void-returning method treated as a 'write method' (setter) has a parameter count that is neither 1 (simple setter) nor 2 (indexed setter). ExtendedBeanInfo inspects setter-like methods during construction and rejects ones that do not match JavaBeans conventions.

Solutions

  1. Rename or remove the offending setXxx method so it has exactly 1 (simple) or 2 (indexed, first int) parameters.
  2. Use a different method name prefix (e.g. withFoo) for fluent builders to avoid being treated as a setter.
  3. If the class is from a third party, avoid passing it through Spring's ExtendedBeanInfo; isolate it.

Example fix

// before
public void setItems(int i, String value, boolean flag) { ... }

// after - conform to indexed-setter convention or rename
public void setItem(int i, String value) { ... }
// or use a non-setter name
public Builder withItem(int i, String value) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// before exposing a class to ExtendedBeanInfo
for (Method m : cls.getMethods()) {
    if (m.getName().startsWith("set") && m.getName().length() > 3) {
        int n = m.getParameterCount();
        if (n != 1 && n != 2) {
            throw new IllegalStateException("non-conformant setter: " + m);
        }
    }
}

Type guard

static boolean settersConform(Class<?> c) {
    for (Method m : c.getMethods()) {
        if (m.getName().startsWith("set") && m.getName().length() > 3) {
            int n = m.getParameterCount();
            if (n != 1 && n != 2) return false;
        }
    }
    return true;
}

Prevention

When it happens

Trigger: ExtendedBeanInfo is built over a BeanInfo; for each method it treats as a setter, if the parameter count is not 1 or 2 it throws. Typically triggered when a class has a method named setXxx with zero or 3+ parameters being picked up by the extended introspector.

Common situations: A class with an unconventional method like setFoo() with no args, setFoo(a, b, c), or a fluent builder setFoo(a, b) intended to be a setter but misinterpreted. Also seen with libraries that generate odd setter-shaped methods.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/9328d84fb84d490b. Report an issue: GitHub.

Appendix: source

Thrown at spring-beans/src/main/java/org/springframework/beans/ExtendedBeanInfo.java:184

				existingPd.setWriteMethod(method);
			}
		}
		else if (nParams == 2) {
			if (existingPd == null) {
				this.propertyDescriptors.add(
						new SimpleIndexedPropertyDescriptor(propertyName, null, null, null, method));
			}
			else if (existingPd instanceof IndexedPropertyDescriptor indexedPd) {
				indexedPd.setIndexedWriteMethod(method);
			}
			else {
				this.propertyDescriptors.remove(existingPd);
				this.propertyDescriptors.add(new SimpleIndexedPropertyDescriptor(
						propertyName, existingPd.getReadMethod(), existingPd.getWriteMethod(), null, method));
			}
		}
		else {
			throw new IllegalArgumentException("Write method must have exactly 1 or 2 parameters: " + method);
		}
	}

	private @Nullable PropertyDescriptor findExistingPropertyDescriptor(String propertyName, Class<?> propertyType) {
		for (PropertyDescriptor pd : this.propertyDescriptors) {
			final Class<?> candidateType;
			final String candidateName = pd.getName();
			if (pd instanceof IndexedPropertyDescriptor indexedPd) {
				candidateType = indexedPd.getIndexedPropertyType();
				if (candidateName.equals(propertyName) &&
						(candidateType.equals(propertyType) || candidateType.equals(propertyType.componentType()))) {
					return pd;
				}
			}
			else {
				candidateType = pd.getPropertyType();
				if (candidateName.equals(propertyName) &&
						(candidateType.equals(propertyType) || propertyType.equals(candidateType.componentType()))) {

View on GitHub (pinned to 69bf83ad71)