apache/shenyu · error · IllegalStateException
load extension resources error,subClass subtype is not of…
Error message
load extension resources error,subClass subtype is not of clazz
What it means
loadClass verifies every class found in an SPI resource file is actually assignable to the SPI interface (clazz.isAssignableFrom). If a registered classPath names a class that does not implement/extend the interface, this IllegalStateException is thrown: '<subClass> subtype is not of <clazz>'.
Solutions
- Ensure the mapped class implements the SPI interface (or extends it)
- Fix the classPath entry in META-INF/shenyu/<interface-fqcn> to point at the correct implementation
- Rename/remove resource files that were copied from another interface
- After refactoring, update both the class package and its SPI registration file
Example fix
// before (META-INF/shenyu/org.apache.shenyu.spi.LoadBalance) random=org.apache.shenyu.spi.hash.HashImpl // does not implement LoadBalance // after random=org.apache.shenyu.spi.balance.RandomLoadBalance
Defensive patterns
Strategy: validation
Validate before calling
if (!LoadBalance.class.isAssignableFrom(implClass)) { throw new IllegalStateException(implClass + " must implement LoadBalance before registration"); } Try / catch
try { T ext = loader.getJoin(name); } catch (IllegalStateException e) { log.error("Bad SPI registration: {}", e.getMessage()); throw e; } Prevention
- Never copy META-INF/shenyu/ files between interfaces without renaming
- Keep resource file name exactly the interface FQCN
- Add unit tests loading every registered extension
When it happens
Trigger: A META-INF/shenyu/<interface-fqcn> file maps a name to a class that does not implement that interface.
Common situations: Copy-pasted resource file entries pointing at the wrong class; class no longer implements the interface after a refactor; wrong resource file name so entries belong to another interface; duplicate resource files merged from multiple jars.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- load extension resources error,subClass without @Join…
- doRegister Failed to execute, because selectorDO object is…
- plugin not enabled for current namespace or plugin not…
- client register param must config the appName or contextPath
- If the preMatch method was implemented ,the preParse method…
AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12).
Data as JSON: /api/errors/7c7e285fe8331b7d.
Report an issue: GitHub.
Appendix: source
Thrown at shenyu-spi/src/main/java/org/apache/shenyu/spi/ExtensionLoader.java:308
String classPath = (String) v;
if (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(classPath)) {
try {
loadClass(classes, name, classPath);
} catch (ClassNotFoundException e) {
throw new IllegalStateException("load extension resources error", e);
}
}
});
} catch (IOException e) {
throw new IllegalStateException("load extension resources error", e);
}
}
private void loadClass(final Map<String, ClassEntity> classes,
final String name, final String classPath) throws ClassNotFoundException {
Class<?> subClass = Objects.nonNull(this.classLoader) ? Class.forName(classPath, true, this.classLoader) : Class.forName(classPath);
if (!clazz.isAssignableFrom(subClass)) {
throw new IllegalStateException("load extension resources error," + subClass + " subtype is not of " + clazz);
}
if (!subClass.isAnnotationPresent(Join.class)) {
throw new IllegalStateException("load extension resources error," + subClass + " without @" + Join.class + " annotation");
}
ClassEntity oldClassEntity = classes.get(name);
if (Objects.isNull(oldClassEntity)) {
Join joinAnnotation = subClass.getAnnotation(Join.class);
ClassEntity classEntity = new ClassEntity(name, joinAnnotation.order(), subClass, joinAnnotation.isSingleton());
classes.put(name, classEntity);
} else if (!Objects.equals(oldClassEntity.getClazz(), subClass)) {
throw new IllegalStateException("load extension resources error,Duplicate class " + clazz.getName() + " name "
+ name + " on " + oldClassEntity.getClazz().getName() + " or " + subClass.getName());
}
}
/**
* The type Holder.
*View on GitHub (pinned to 567142e072)