spring-projects/spring-framework · error · IllegalStateException
Could not find original class structure
Error message
Could not find original class structure
What it means
Thrown as an IllegalStateException during deserialization of a DependencyDescriptor: readObject restores the reflective Field/MethodParameter handles from the stored declaring class and member name; if the class no longer has that field/method/constructor (renamed, removed, signature changed, class missing), the reflective lookup throws and is wrapped with this message.
Solutions
- Ensure both producer and consumer of the serialized descriptor run the same application/class versions so the member still exists.
- Avoid serializing DependencyDescriptor across version boundaries; pass plain bean names/types and re-resolve on the receiving side.
- If you control the injection point, keep the field/method name and signature stable across versions, or invalidate caches after refactors.
- Invalidate or migrate any persistent cache holding serialized descriptors when the class structure changes.
- Inspect the 'caused by' (NoSuchFieldException / NoSuchMethodException) to find which member is missing, then restore or rename it back.
Example fix
// before: serializing a DependencyDescriptor across versions // node A (v1): field 'orderRepo' -> node B (v2): field renamed 'repository' ObjectOutputStream oos = ...; oos.writeObject(dependencyDescriptor); // after: don't ship the descriptor; ship the bean name and re-resolve oos.writeObject(descriptor.getDependencyType()); oos.writeObject(beanName); // receiver: beanFactory.getBean(beanName, type);
Defensive patterns
Strategy: validation
Validate before calling
// Verify the reflective member still exists before deserializing/using
Class<?> c = descriptor.getDeclaringClass();
if (descriptor.getFieldName() != null) {
c.getDeclaredField(descriptor.getFieldName()); // throws if missing
} Prevention
- Do not serialize DependencyDescriptor across application versions.
- Pass plain bean name + type over the wire and re-resolve on the receiver.
- Invalidate cached descriptors when class structure changes.
- Keep field/method names stable if descriptors must be cached.
When it happens
Trigger: Deserializing a DependencyDescriptor (across an RPC boundary, in a session, or cached) on a JVM where the declaring class's structure does not match what was serialized: getDeclaredField/getDeclaredMethod/getDeclaredConstructor fails. Triggered inside readObject when reconstructing this.field or this.methodParameter.
Common situations: Distributing a DependencyDescriptor between nodes running different versions of the application where a field/method was renamed or deleted; serializing a descriptor that points at a class that was later removed; refactoring an @Autowired field's name after a descriptor was cached; classloader differences hiding the expected member; cross-major Spring upgrade that changed reflective metadata.
Related errors
- cannot be found on
- Failed to instantiate method
- Failed to invoke init method
- Service locator exception
- targetField is required
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/3f79df64b06afa3f.
Report an issue: GitHub.
Appendix: source
Thrown at spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java:434
if (this.fieldName != null) {
this.field = this.declaringClass.getDeclaredField(this.fieldName);
}
else {
if (this.methodName != null) {
this.methodParameter = new MethodParameter(
this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
}
else {
this.methodParameter = new MethodParameter(
this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
}
for (int i = 1; i < this.nestingLevel; i++) {
this.methodParameter = this.methodParameter.nested();
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Could not find original class structure", ex);
}
}
}
View on GitHub (pinned to 69bf83ad71)