alibaba/canal · error · IllegalArgumentException
Extension type == null
Error message
Extension type == null
What it means
Thrown by ExtensionLoader.getExtensionLoader(type, policy) when the supplied Class<T> type is null. This is a programming-error guard at the very start of SPI loader acquisition; type must be a non-null @SPI-annotated interface before any extension lookup can occur.
Source
Thrown at connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java:72
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
private String cachedDefaultName;
private ConcurrentHashMap<String, IllegalStateException> exceptions = new ConcurrentHashMap<>();
private static <T> boolean withExtensionAnnotation(Class<T> type) {
return type.isAnnotationPresent(SPI.class);
}
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
return getExtensionLoader(type, DEFAULT_CLASSLOADER_POLICY);
}
@SuppressWarnings("unchecked")
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type, String classLoaderPolicy) {
if (type == null) throw new IllegalArgumentException("Extension type == null");
if (!type.isInterface()) {
throw new IllegalArgumentException("Extension type(" + type + ") is not interface!");
}
if (!withExtensionAnnotation(type)) {
throw new IllegalArgumentException("Extension type(" + type + ") is not extension, because WITHOUT @"
+ SPI.class.getSimpleName() + " Annotation!");
}
ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type, classLoaderPolicy));
loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;
}
public ExtensionLoader(Class<?> type){
this.type = type;View on GitHub (pinned to 87be50e876)
Solutions
- Ensure a non-null @SPI interface Class is passed, e.g. ExtensionLoader.getExtensionLoader(CanalMQProducer.class).
- Fix the upstream null (initialize the type field / pass the concrete interface constant).
Example fix
// before Class<?> type = resolveOrNull(); ExtensionLoader.getExtensionLoader(type); // after ExtensionLoader.getExtensionLoader(CanalMQProducer.class);
Defensive patterns
Strategy: validation
Validate before calling
// Ensure type is non-null before acquiring a loader
if (type == null) {
throw new IllegalArgumentException("extension type must not be null at " + caller);
}
ExtensionLoader.getExtensionLoader(type); Try / catch
try {
ExtensionLoader.getExtensionLoader(type);
} catch (IllegalArgumentException e) {
// programming error: fix the caller passing null
throw new IllegalStateException("BUG: null extension type", e);
} Prevention
- Never forward a possibly-null type into getExtensionLoader.
- Pass the concrete interface constant directly.
When it happens
Trigger: Passing a null class reference to getExtensionLoader — typically because a constant/field that should hold the interface resolved to null (e.g. dead code path, class stripping, or a generic helper that forwards a possibly-null type).
Common situations: Refactoring that left a null where an interface type was expected; DI/proxy code passing a null type through reflection; calling getExtensionLoader from a code path where the type was never initialized.
Related errors
- Extension type({}) is not interface!
- Extension type({}) is not extension, because WITHOUT @{} Ann
- Extension name == null
- Extension instance(name: {}, class: {}) could not be instan
- Extension instance(name: {}, class: {}) could not be instan
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/528447e5afa822cf.
Report an issue: GitHub.