{"record":{"id":"28d3a4a2bf968fe0","repo":"apache/dubbo","slug":"extension-type-null","errorCode":null,"errorMessage":"Extension type == null","messagePattern":"Extension type == null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java","lineNumber":70,"sourceCode":"            this.extensionPostProcessors.add(processor);\n        }\n    }\n\n    public List<ExtensionPostProcessor> getExtensionPostProcessors() {\n        return extensionPostProcessors;\n    }\n\n    @Override\n    public ExtensionDirector getExtensionDirector() {\n        return this;\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {\n        checkDestroyed();\n        if (type == null) {\n            throw new IllegalArgumentException(\"Extension type == null\");\n        }\n        if (!type.isInterface()) {\n            throw new IllegalArgumentException(\"Extension type (\" + type + \") is not an interface!\");\n        }\n        if (!withExtensionAnnotation(type)) {\n            throw new IllegalArgumentException(\"Extension type (\" + type\n                    + \") is not an extension, because it is NOT annotated with @\" + SPI.class.getSimpleName() + \"!\");\n        }\n\n        // 1. find in local cache\n        ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);\n\n        ExtensionScope scope = extensionScopeMap.get(type);\n        if (scope == null) {\n            SPI annotation = type.getAnnotation(SPI.class);\n            scope = annotation.scope();\n            extensionScopeMap.put(type, scope);\n        }","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/dubbo/blob/3a3043227f5571d25eb2889de5bca22f2914843b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java#L52-L88","documentation":"Thrown by ExtensionDirector.getExtensionLoader(Class<T> type) when the type argument is null. Dubbo's SPI system requires a non-null interface class to resolve the corresponding ExtensionLoader. This is the first guard in the extension resolution pipeline — a null type means no meaningful lookup is possible.","triggerScenarios":"Calling extensionDirector.getExtensionLoader(null) directly, or more commonly passing a class reference that was resolved to null at runtime (e.g., a Class.forName() that failed silently, a static field that was not initialized, or a class that was shaded/relocated away during a dependency upgrade).","commonSituations":"Maven shade plugin relocated a package but code still references the old class constant which resolved to null. A custom ScopeModel or ExtensionDirector subclass forgot to pass the type. A plugin/module integration passes a class loaded from a different ClassLoader that returned null. After a Dubbo version upgrade where an SPI interface was renamed or moved.","solutions":["Inspect the stack trace to find which code path passes null to getExtensionLoader and trace the source of the Class<T> argument.","Ensure the class reference is loaded via the correct ClassLoader and is not null before calling getExtensionLoader.","Check that the relevant Dubbo module dependency (e.g., dubbo-rpc-api, dubbo-registry-api) is on the classpath so that the interface class constant resolves.","If using shade/relocate, verify the relocation rules cover the package of the SPI interface."],"exampleFix":"// before\nExtensionLoader<MySpi> loader = director.getExtensionLoader(spiClass); // spiClass is null\n\n// after\nif (spiClass == null) {\n    throw new IllegalStateException(\"MySpi class not loaded — check dubbo-rpc-api dependency\");\n}\nExtensionLoader<MySpi> loader = director.getExtensionLoader(spiClass);","handlingStrategy":"validation","validationCode":"if (type == null) {\n    throw new IllegalArgumentException(\"SPI type must not be null — check classpath and ClassLoader\");\n}\nExtensionLoader<T> loader = director.getExtensionLoader(type);","typeGuard":"static <T> boolean isValidSpiType(Class<T> type) {\n    return type != null && type.isInterface() && type.isAnnotationPresent(SPI.class);\n}","tryCatchPattern":"try {\n    ExtensionLoader<T> loader = director.getExtensionLoader(type);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Extension type == null\")) {\n        log.error(\"SPI type was null — likely a missing dependency or ClassLoader issue\", e);\n    }\n    throw e;\n}","preventionTips":["Always resolve SPI interface class constants through the same ClassLoader that loaded Dubbo.","Use @SPI-annotated interface class constants directly (e.g., Protocol.class) rather than dynamic Class.forName without null checks.","In test code, verify classpath includes the Dubbo module providing the SPI interface."],"tags":["dubbo-spi","null-check","extension-system","configuration"],"backgroundTag":null,"analyzedSha":"3a3043227f5571d25eb2889de5bca22f2914843b","analyzedAt":"2026-08-14T00:43:19.853Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}