spring-projects/spring-framework · critical · IllegalStateException
The version of aspectjtools.jar / aspectjweaver.jar on the…
Error message
The version of aspectjtools.jar / aspectjweaver.jar on the classpath is incompatible with this version of Spring: {0} What it means
Thrown by the static initializer of RuntimeTestWalker when it cannot find expected internal fields (residualTest in ShadowMatchImpl, varType in ReflectionVar, or myClass in ReflectionBasedReferenceTypeDelegate) in the AspectJ weaver classes on the classpath. RuntimeTestWalker reflects into AspectJ internals to query runtime test types; if the field layout changed between versions, this indicates an incompatible aspectjtools.jar / aspectjweaver.jar version.
Solutions
- Align the AspectJ version with your Spring version — check the Spring framework reference docs for the expected aspectjweaver version
- Use Spring's spring-framework-bom (or spring-boot-dependencies BOM) to manage compatible transitive versions
- Run mvn dependency:tree or gradle dependencies to find conflicting aspectjweaver versions and exclude transitive mismatches
Example fix
<!-- before: mismatched versions --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> <!-- after: aligned with Spring's expected version --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.22</version> </dependency>
Defensive patterns
Strategy: validation
Validate before calling
// At build/setup time, verify the aspectjweaver version matches the Spring version's expectation
// Check the loaded version at runtime:
String ajVersion = org.aspectj.lang.Aspects.class.getPackage().getImplementationVersion();
// Compare against Spring's documented compatible version (e.g., 1.9.x for Spring 6.x)
if (ajVersion == null || !ajVersion.startsWith("1.9.")) {
logger.warn("aspectjweaver version " + ajVersion + " may be incompatible with this Spring version");
} Prevention
- Use spring-framework-bom or spring-boot-dependencies to auto-manage compatible AspectJ versions
- After any Spring upgrade, verify aspectjweaver/aspectjtools versions are still compatible
- Run mvn dependency:tree | grep aspectj to catch transitive version conflicts
When it happens
Trigger: A classpath with an aspectjweaver/aspectjtools version older or newer than the one Spring AOP was compiled and tested against. Since this is a static initializer, the error surfaces at class-loading time of RuntimeTestWalker (triggered during the first pointcut match), not at construction.
Common situations: Upgrading Spring without upgrading AspectJ (or vice versa), pulling in a transitive incompatible AspectJ version from another dependency, or running on a newer Java version that requires a newer AspectJ.
Related errors
- Returning name ' ' is neither a valid argument name nor the…
- Throwing name ' ' is neither a valid argument name nor the…
- Advice method [ ] requires arguments to be bound by name…
- Advice must be declared inside an aspect type: Offending…
- An advice method can never be a constructor
AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09).
Data as JSON: /api/errors/93f44a406d4167b4.
Report an issue: GitHub.
Appendix: source
Thrown at spring-aop/src/main/java/org/springframework/aop/aspectj/RuntimeTestWalker.java:76
* @since 2.0
*/
class RuntimeTestWalker {
private static final Field residualTestField;
private static final Field varTypeField;
private static final Field myClassField;
static {
try {
residualTestField = ShadowMatchImpl.class.getDeclaredField("residualTest");
varTypeField = ReflectionVar.class.getDeclaredField("varType");
myClassField = ReflectionBasedReferenceTypeDelegate.class.getDeclaredField("myClass");
}
catch (NoSuchFieldException ex) {
throw new IllegalStateException("The version of aspectjtools.jar / aspectjweaver.jar " +
"on the classpath is incompatible with this version of Spring: " + ex);
}
}
private final @Nullable Test runtimeTest;
public RuntimeTestWalker(ShadowMatch shadowMatch) {
try {
ReflectionUtils.makeAccessible(residualTestField);
this.runtimeTest = (Test) residualTestField.get(shadowMatch);
}
catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
}
View on GitHub (pinned to 69bf83ad71)