apache/dubbo · error · IllegalStateException

More than 1 default extension name on extension {}: {}

Error message

More than 1 default extension name on extension {}: {}

What it means

Thrown by cacheDefaultExtensionName() when the @SPI annotation's value() on an SPI interface contains more than one comma-separated name after trimming. The @SPI annotation declares the default extension name; Dubbo only allows exactly one default. A value like @SPI("a,b") is rejected because getDefaultExtension() cannot resolve ambiguity.

Source

Thrown at dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java:1036

            }
        }
    }

    /**
     * extract and cache default extension name if exists
     */
    private void cacheDefaultExtensionName() {
        final SPI defaultAnnotation = type.getAnnotation(SPI.class);
        if (defaultAnnotation == null) {
            return;
        }

        String value = defaultAnnotation.value();
        if ((value = value.trim()).length() > 0) {
            String[] names = NAME_SEPARATOR.split(value);
            if (names.length > 1) {
                throw new IllegalStateException("More than 1 default extension name on extension " + type.getName()
                        + ": " + Arrays.toString(names));
            }
            if (names.length == 1) {
                cachedDefaultName = names[0];
            }
        }
    }

    private void loadDirectoryInternal(
            Map<String, Class<?>> extensionClasses, LoadingStrategy loadingStrategy, String type)
            throws InterruptedException {
        String fileName = loadingStrategy.directory() + type;
        try {
            List<ClassLoader> classLoadersToLoad = new LinkedList<>();

            // try to load from ExtensionLoader's ClassLoader first
            if (loadingStrategy.preferExtensionClassLoader()) {
                ClassLoader extensionLoaderClassLoader = ExtensionLoader.class.getClassLoader();

View on GitHub (pinned to 3a3043227f)

Solutions

  1. Edit the SPI interface annotation to contain exactly one default name: @SPI("singleName").
  2. If you need conditional/multiple extension selection, use @Activate annotations on implementations or select by name explicitly via getExtension(name) instead of relying on a default.
  3. If you intended round-robin or fallback, implement a custom selector rather than abusing the default.

Example fix

// before
@SPI("dubbo,rest")
public interface Protocol { ... }
// throws [145] at load time

// after
@SPI("dubbo")
public interface Protocol { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the @SPI annotation at build/test time
SPI ann = MySpi.class.getAnnotation(SPI.class);
if (ann != null) {
    String[] names = ann.value().trim().split(",");
    if (names.length > 1) throw new IllegalStateException("@SPI has multiple defaults: " + ann.value());
}

Prevention

When it happens

Trigger: An SPI interface is annotated with @SPI containing multiple names, e.g. @SPI("dubbo,mock") or @SPI("a,b,c"). cacheDefaultExtensionName() is called during the first extension-class load and splits on NAME_SEPARATOR (comma); if more than one token results, it throws immediately.

Common situations: A custom SPI interface mistakenly lists multiple defaults; copy-paste from an example that intended multiple Activate values (which use different semantics); a fork that changed a single-default @SPI to list fallbacks thinking it would be tried in order.

Related errors


AI-assisted analysis of apache/dubbo@3a3043227f (2026-08-14). Data as JSON: /api/errors/70b9e2c523f85128. Report an issue: GitHub.