spring-projects/spring-framework · error · FatalBeanException
Failed to obtain BeanInfo for class [{beanClass.getName()}]
Error message
Failed to obtain BeanInfo for class [{beanClass.getName()}] What it means
Thrown as FatalBeanException wrapping a java.beans.IntrospectionException when CachedIntrospectionResults fails to obtain BeanInfo for a class during the initial introspection pass (getBeanInfo(beanClass) or the introspection of methods/interfaces/plained accessors). This typically signals that the JDK Introspector rejected the class's bean metadata.
Source
Thrown at spring-beans/src/main/java/org/springframework/beans/CachedIntrospectionResults.java:299
readMethodNames.add(readMethod.getName());
}
}
// Explicitly check implemented interfaces for setter/getter methods as well,
// in particular for interface default methods.
Class<?> currClass = beanClass;
while (currClass != null && currClass != Object.class) {
introspectInterfaces(beanClass, currClass, readMethodNames);
currClass = currClass.getSuperclass();
}
// Check for record-style accessors without prefix: for example, "lastName()"
// - accessor method directly referring to instance field of same name
// - same convention for component accessors of Java 15 record classes
introspectPlainAccessors(beanClass, readMethodNames);
}
catch (IntrospectionException ex) {
throw new FatalBeanException("Failed to obtain BeanInfo for class [" + beanClass.getName() + "]", ex);
}
}
private void introspectInterfaces(Class<?> beanClass, Class<?> currClass, Set<String> readMethodNames)
throws IntrospectionException {
for (Class<?> ifc : currClass.getInterfaces()) {
if (!ClassUtils.isJavaLanguageInterface(ifc)) {
for (PropertyDescriptor pd : getBeanInfo(ifc).getPropertyDescriptors()) {
PropertyDescriptor existingPd = this.propertyDescriptors.get(pd.getName());
if (existingPd == null ||
(existingPd.getReadMethod() == null && pd.getReadMethod() != null)) {
// GenericTypeAwarePropertyDescriptor leniently resolves a set* write method
// against a declared read method, so we prefer read method descriptors here.
pd = buildGenericTypeAwarePropertyDescriptor(beanClass, pd);
if (pd.getWriteMethod() == null &&
isInvalidReadOnlyPropertyType(pd.getPropertyType(), beanClass)) {
// Ignore read-only properties such as ClassLoader - no need to bind to thoseView on GitHub (pinned to 69bf83ad71)
Solutions
- Inspect the wrapped IntrospectionException cause to identify the offending property/method.
- Fix conflicting getter/setter signatures (matching types, int index for indexed accessors).
- Exclude or rename the conflicting accessor that is confusing the Introspector.
- If unavoidable, avoid wrapping that class directly with a BeanWrapper; use field access (DirectFieldAccessor) or map it manually.
Example fix
// before // class has: String getName(); void setName(int name); -> conflicting types BeanWrapper wrapper = new BeanWrapperImpl(myBean); // after - align accessor types // String getName(); void setName(String name);
Defensive patterns
Strategy: try-catch
Type guard
static boolean introspectable(Class<?> c) {
try { java.beans.Introspector.getBeanInfo(c); return true; }
catch (java.beans.IntrospectionException e) { return false; }
} Try / catch
try {
BeanWrapper w = new BeanWrapperImpl(bean);
} catch (FatalBeanException ex) {
// cause is IntrospectionException; identify the offending property
log.error("introspection failed for {}", bean.getClass(), ex.getCause());
} Prevention
- Keep getter/setter types consistent per property name.
- Run a quick java.beans.Introspector.getBeanInfo(cls) smoke test in unit tests for shared DTOs.
- Avoid conflicting overloaded accessors that the Introspector cannot reconcile.
When it happens
Trigger: Triggered when CachedIntrospectionResults.forClass(beanClass) is first created for a BeanWrapper or BeanUtils call, and the underlying java.beans.Introspector.getBeanInfo throws IntrospectionException (e.g. mismatched getter/setter types, an indexed property descriptor that could not be built).
Common situations: A class has getter/setter pairs with incompatible types for the same property name, an overloaded indexed accessor with non-int index, or a class generated by a code generator/bytecode library that emits methods the Introspector cannot reconcile. Frequently seen with Lombok @Delegate or with manually written conflicting accessors.
Related errors
- Failed to re-introspect class [{beanClass.getName()}]
- Nested property in path '{propertyName}' does not exist
- No property handler found
- Invalid array index in property path '{tokens.canonicalName}
- Cannot set element with index {index} in List of size {size}
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/8567973ec18ea960.
Report an issue: GitHub.