{"record":{"id":"7c7e285fe8331b7d","repo":"apache/shenyu","slug":"load-extension-resources-error-subclass-subtype-is-not-of","errorCode":null,"errorMessage":"load extension resources error,subClass subtype is not of clazz","messagePattern":"load extension resources error,subClass subtype is not of clazz","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"shenyu-spi/src/main/java/org/apache/shenyu/spi/ExtensionLoader.java","lineNumber":308,"sourceCode":"                String classPath = (String) v;\n                if (StringUtils.isNotBlank(name) && StringUtils.isNotBlank(classPath)) {\n                    try {\n                        loadClass(classes, name, classPath);\n                    } catch (ClassNotFoundException e) {\n                        throw new IllegalStateException(\"load extension resources error\", e);\n                    }\n                }\n            });\n        } catch (IOException e) {\n            throw new IllegalStateException(\"load extension resources error\", e);\n        }\n    }\n    \n    private void loadClass(final Map<String, ClassEntity> classes,\n                           final String name, final String classPath) throws ClassNotFoundException {\n        Class<?> subClass = Objects.nonNull(this.classLoader) ? Class.forName(classPath, true, this.classLoader) : Class.forName(classPath);\n        if (!clazz.isAssignableFrom(subClass)) {\n            throw new IllegalStateException(\"load extension resources error,\" + subClass + \" subtype is not of \" + clazz);\n        }\n        if (!subClass.isAnnotationPresent(Join.class)) {\n            throw new IllegalStateException(\"load extension resources error,\" + subClass + \" without @\" + Join.class + \" annotation\");\n        }\n        ClassEntity oldClassEntity = classes.get(name);\n        if (Objects.isNull(oldClassEntity)) {\n            Join joinAnnotation = subClass.getAnnotation(Join.class);\n            ClassEntity classEntity = new ClassEntity(name, joinAnnotation.order(), subClass, joinAnnotation.isSingleton());\n            classes.put(name, classEntity);\n        } else if (!Objects.equals(oldClassEntity.getClazz(), subClass)) {\n            throw new IllegalStateException(\"load extension resources error,Duplicate class \" + clazz.getName() + \" name \"\n                    + name + \" on \" + oldClassEntity.getClazz().getName() + \" or \" + subClass.getName());\n        }\n    }\n    \n    /**\n     * The type Holder.\n     *","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/apache/shenyu/blob/567142e07261b3e615ae8850b30f4421f455cc5d/shenyu-spi/src/main/java/org/apache/shenyu/spi/ExtensionLoader.java#L290-L326","documentation":"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>'.","triggerScenarios":"A META-INF/shenyu/<interface-fqcn> file maps a name to a class that does not implement that interface.","commonSituations":"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.","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"],"exampleFix":"// before (META-INF/shenyu/org.apache.shenyu.spi.LoadBalance)\nrandom=org.apache.shenyu.spi.hash.HashImpl // does not implement LoadBalance\n// after\nrandom=org.apache.shenyu.spi.balance.RandomLoadBalance","handlingStrategy":"validation","validationCode":"if (!LoadBalance.class.isAssignableFrom(implClass)) { throw new IllegalStateException(implClass + \" must implement LoadBalance before registration\"); }","typeGuard":null,"tryCatchPattern":"try { T ext = loader.getJoin(name); } catch (IllegalStateException e) { log.error(\"Bad SPI registration: {}\", e.getMessage()); throw e; }","preventionTips":["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"],"tags":["spi","type-mismatch","registration"],"backgroundTag":"type-mismatch","analyzedSha":"567142e07261b3e615ae8850b30f4421f455cc5d","analyzedAt":"2026-09-12T10:08:21.293Z","contentChangedAt":"2026-09-12T10:08:21.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}