spring-projects/spring-framework · error · IllegalArgumentException
[{}] is not an interface
Error message
[{}] is not an interface What it means
Thrown by AdvisedSupport.addInterface when the supplied Class is not actually a Java interface (!ifc.isInterface()). JDK dynamic proxies can only implement interfaces, so Spring rejects any concrete class or enum passed as a proxied interface to keep the advisor model consistent. This is a hard validation enforced at configuration time.
Source
Thrown at spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java:234
/**
* Set the interfaces to be proxied.
*/
public void setInterfaces(Class<?>... interfaces) {
Assert.notNull(interfaces, "Interfaces must not be null");
this.interfaces.clear();
for (Class<?> ifc : interfaces) {
addInterface(ifc);
}
}
/**
* Add a new proxied interface.
* @param ifc the additional interface to proxy
*/
public void addInterface(Class<?> ifc) {
Assert.notNull(ifc, "Interface must not be null");
if (!ifc.isInterface()) {
throw new IllegalArgumentException("[" + ifc.getName() + "] is not an interface");
}
if (!this.interfaces.contains(ifc)) {
this.interfaces.add(ifc);
adviceChanged();
}
}
/**
* Remove a proxied interface.
* <p>Does nothing if the given interface isn't proxied.
* @param ifc the interface to remove from the proxy
* @return {@code true} if the interface was removed; {@code false}
* if the interface was not found and hence could not be removed
*/
public boolean removeInterface(Class<?> ifc) {
return this.interfaces.remove(ifc);
}
View on GitHub (pinned to e8729d0438)
Solutions
- Pass only interface types to addInterface/setInterfaces; extract or identify the interface the target implements (e.g. MyService instead of MyServiceImpl).
- If you really need to proxy a concrete class, enable proxyTargetClass=true (CGLIB) rather than adding the class as an interface.
- Add an isInterface() guard in any generic helper that builds the interface array.
Example fix
// before proxyFactory.setInterfaces(MyServiceImpl.class); // concrete class // after proxyFactory.setInterfaces(MyService.class); // the interface // or, to proxy the concrete class itself: proxyFactory.setProxyTargetClass(true); proxyFactory.setTarget(new MyServiceImpl());
Defensive patterns
Strategy: validation
Validate before calling
Class<?> ifc = MyServiceImpl.class;
if (!ifc.isInterface()) {
throw new IllegalArgumentException(
ifc.getName() + " is not an interface; pass an interface or enable proxyTargetClass");
} Type guard
static boolean isProxiableInterface(Class<?> c) {
return c != null && c.isInterface();
} Prevention
- Keep a dedicated list of interface classes (never implementations) for setInterfaces.
- Enable proxyTargetClass=true if you genuinely need to proxy a concrete class.
- In generic helpers, assert isInterface() before addInterface.
When it happens
Trigger: Calling proxyFactory.addInterface(MyConcreteClass.class) or advised.setInterfaces(SomeClass.class) where the argument is a class rather than an interface; using proxyTargetClass=false (JDK proxy mode) but adding a concrete class to the interface list; programmatic AspectJ-style wiring mistakes.
Common situations: Confusing the target class (which can be concrete) with proxied interfaces; accidentally passing an abstract class; generic helper code that passes arbitrary Class<?> without checking isInterface(); migrating from CGLIB to JDK proxy without converting the interface list.
Related errors
- MethodInvocation is not a Spring ProxyMethodInvocation: {}
- Property 'target' is required
- Could not generate CGLIB subclass of {advised.getTargetClass
- Not running in a ConfigurableBeanFactory: {beanFactory}
- 'argumentNames' property of AbstractAspectJAdvice contains a
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/b9fadff730a3d9a3.json.
Report an issue: GitHub.