spring-projects/spring-framework · error · AopInvocationException

Could not access method [{method}]

Error message

Could not access method [{method}]

What it means

invokeJoinpointUsingReflection catches IllegalAccessException and InaccessibleObjectException from Method.invoke (even after ReflectionUtils.makeAccessible) and wraps them as AopInvocationException 'Could not access method'. The JVM refused the reflective call, most often because the Java Platform Module System (JPMS) blocks access to a class in another module.

Source

Thrown at spring-aop/src/main/java/org/springframework/aop/support/AopUtils.java:371

		// Use reflection to invoke the method.
		try {
			Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
			ReflectionUtils.makeAccessible(originalMethod);
			return (COROUTINES_REACTOR_PRESENT && KotlinDetector.isSuspendingFunction(originalMethod) ?
					KotlinDelegate.invokeSuspendingFunction(originalMethod, target, args) : originalMethod.invoke(target, args));
		}
		catch (InvocationTargetException ex) {
			// Invoked method threw a checked exception.
			// We must rethrow it. The client won't see the interceptor.
			throw ex.getTargetException();
		}
		catch (IllegalArgumentException ex) {
			throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
					method + "] on target [" + target + "]", ex);
		}
		catch (IllegalAccessException | InaccessibleObjectException ex) {
			throw new AopInvocationException("Could not access method [" + method + "]", ex);
		}
	}


	/**
	 * Inner class to avoid a hard dependency on Kotlin at runtime.
	 */
	private static class KotlinDelegate {

		public static Object invokeSuspendingFunction(Method method, @Nullable Object target, @Nullable Object... args) {
			Continuation<?> continuation = (Continuation<?>) args[args.length -1];
			Assert.state(continuation != null, "No Continuation available");
			CoroutineContext context = continuation.getContext().minusKey(Job.Key);
			return CoroutinesUtils.invokeSuspendingFunction(context, method, target, args);
		}
	}

}

View on GitHub (pinned to e8729d0438)

Solutions

  1. Add the appropriate --add-opens=module/package=ALL-UNNAMED JVM argument for the offending package.
  2. Make the target method public or package-private so makeAccessible succeeds.
  3. Avoid advising/reflecting into JDK-internal classes; use supported APIs instead.

Example fix

# before
java -jar app.jar
# -> Could not access method [java.base/java.lang.X.y] (InaccessibleObjectException)

# after
java --add-opens=java.base/java.lang=ALL-UNNAMED -jar app.jar
Defensive patterns

Strategy: validation

Validate before calling

try {
    method.setAccessible(true); // fails fast under JPMS if not open
} catch (InaccessibleObjectException ex) {
    // require --add-opens for method's declaring package
}

Type guard

boolean isAccessibleInModule(java.lang.reflect.Method m) {
    try { m.setAccessible(true); return true; }
    catch (InaccessibleObjectException e) { return false; }
}

Try / catch

try {
    return AopUtils.invokeJoinpointUsingReflection(target, method, args);
} catch (AopInvocationException ex) {
    if (ex.getCause() instanceof InaccessibleObjectException) {
        // add --add-opens or widen visibility
    }
    throw ex;
}

Prevention

When it happens

Trigger: Reflectively invoking a non-opened package member (e.g. a JDK internal class, or a class in another module) without the corresponding --add-opens, or a method whose declaring class is inaccessible to the caller module.

Common situations: JDK 9+ strong encapsulation blocking reflective access to java.base internals; advising code that touches JDK internals; sealed library classes; Kotlin/Scala compiler-generated classes with restrictive visibility.

Related errors


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