apache/shenyu · error · IllegalStateException

load extension resources error,Duplicate class clazz name…

Error message

load extension resources error,Duplicate class clazz name name on oldClass or subClass

What it means

ShenYu's SPI ExtensionLoader loads extension implementations from META-INF/shenyu/ resource files, mapping a name to a class. When two different classes claim the same extension name within one extension interface's resources, it cannot decide which one is correct and throws this IllegalStateException during loadResources → loadClass.

Solutions

  1. Rename the extension name in your META-INF/shenyu/<interface-fqcn> file so it is unique
  2. Remove the duplicate/conflicting registration line or the redundant jar containing the conflicting implementation
  3. If the classes are actually identical, delete one of the duplicate declarations

Example fix

// before (META-INF/shenyu/org.apache.shenyu.spi.HttpParamConverter)
timeConverter=org.apache.shenyu.example.TimeConverter
// after (unique name)
myTimeConverter=org.apache.shenyu.example.TimeConverter
Defensive patterns

Strategy: validation

Validate before calling

Map<String,String> names = new HashMap<>();
for (String line : Files.readAllLines(spiFile)) {
    String name = line.split("=", 2)[0].trim();
    if (names.containsKey(name)) throw new IllegalStateException("duplicate SPI name: " + name);
    names.put(name, line);
}

Try / catch

try {
    extension = ExtensionLoader.getExtensionLoader(MySpi.class).getJoin("myName");
} catch (IllegalStateException e) {
    if (e.getMessage().contains("Duplicate class")) {
        log.error("Conflicting SPI registration for name", e);
    } else throw e;
}

Prevention

When it happens

Trigger: Two SPI registration files (or duplicate entries in one file) under META-INF/shenyu/ declare the same extension `name` mapped to different implementation classes of the same @SPI interface.

Common situations: Merging upstream code with a locally added extension that reused an existing name; adding a custom implementation in a jar that collides with a ShenYu built-in extension name; copy-pasting an SPI config line without changing the name key.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/ba912bf8f2e7b7c7. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-spi/src/main/java/org/apache/shenyu/spi/ExtensionLoader.java:319

        }
    }
    
    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.
     *
     * @param <T> the type parameter.
     */
    private static final class Holder<T> {
        
        private volatile T value;
        
        private Integer order;

        /**
         * Gets value.
         *

View on GitHub (pinned to 567142e072)