apache/shenyu · error · IllegalArgumentException

extension clazz (clazz) is not interface!

Error message

extension clazz (clazz) is not interface!

What it means

ShenYu's SPI mechanism (ExtensionLoader.getExtensionLoader) only works with interfaces annotated with @SPI. This IllegalArgumentException is thrown when the Class passed to getExtensionLoader is a concrete class, enum, or other non-interface type. The SPI framework loads implementations via META-INF/shenyu/ resource files keyed by the interface, so only interfaces are valid extension types.

Solutions

  1. Pass the SPI interface type instead of an implementation class
  2. Verify the type is an interface: clazz.isInterface() must be true
  3. Annotate the interface with @org.apache.shenyu.spi.SPI

Example fix

// before
ExtensionLoader<LoadBalanceMockImpl> loader = ExtensionLoader.getExtensionLoader(LoadBalanceMockImpl.class);
// after
ExtensionLoader<LoadBalance> loader = ExtensionLoader.getExtensionLoader(LoadBalance.class);
Defensive patterns

Strategy: validation

Validate before calling

if (!LoadBalance.class.isInterface()) { throw new IllegalArgumentException("must pass an SPI interface"); }
ExtensionLoader<LoadBalance> loader = ExtensionLoader.getExtensionLoader(LoadBalance.class);

Type guard

static <T> boolean isSpiInterface(Class<T> c) { return c.isInterface(); }

Try / catch

try { loader = ExtensionLoader.getExtensionLoader(clazz); } catch (IllegalArgumentException e) { log.error("Bad SPI type: {}", e.getMessage()); throw e; }

Prevention

When it happens

Trigger: Calling ExtensionLoader.getExtensionLoader(SomeConcreteClass.class) where the argument is a class or abstract class rather than an interface.

Common situations: Developer mistakenly passes the implementation class instead of the SPI interface (e.g. getExtensionLoader(LoadBalanceMockImpl.class) instead of getExtensionLoader(LoadBalance.class)); refactoring turned a former interface into a class; copy-paste of the wrong Class literal.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        if (!Objects.equals(clazz, ExtensionFactory.class)) {
            ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getExtensionClassesEntity();
        }
    }
    
    /**
     * Gets extension loader.
     *
     * @param <T>   the type parameter
     * @param clazz the clazz
     * @param cl    the cl
     * @return the extension loader.
     */
    public static <T> ExtensionLoader<T> getExtensionLoader(final Class<T> clazz, final ClassLoader cl) {
        
        Objects.requireNonNull(clazz, "extension clazz is null");
        
        if (!clazz.isInterface()) {
            throw new IllegalArgumentException("extension clazz (" + clazz + ") is not interface!");
        }
        if (!clazz.isAnnotationPresent(SPI.class)) {
            throw new IllegalArgumentException("extension clazz (" + clazz + ") without @" + SPI.class + " Annotation");
        }
        ExtensionLoader<T> extensionLoader = (ExtensionLoader<T>) LOADERS.get(clazz);
        if (Objects.nonNull(extensionLoader)) {
            return extensionLoader;
        }
        LOADERS.putIfAbsent(clazz, new ExtensionLoader<>(clazz, cl));
        return (ExtensionLoader<T>) LOADERS.get(clazz);
    }
    
    /**
     * Gets extension loader.
     *
     * @param <T>   the type parameter
     * @param clazz the clazz
     * @return the extension loader

View on GitHub (pinned to 567142e072)