{"record":{"id":"32715946638a42ec","repo":"alibaba/canal","slug":"extension-name-null-327159","errorCode":null,"errorMessage":"Extension name == null","messagePattern":"Extension name == null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java","lineNumber":107,"sourceCode":"    public ExtensionLoader(Class<?> type){\n        this.type = type;\n        this.classLoaderPolicy = DEFAULT_CLASSLOADER_POLICY;\n    }\n\n    public ExtensionLoader(Class<?> type, String classLoaderPolicy){\n        this.type = type;\n        this.classLoaderPolicy = classLoaderPolicy;\n    }\n\n    /**\n     * 返回指定名字的扩展\n     *\n     * @param name\n     * @return\n     */\n    @SuppressWarnings(\"unchecked\")\n    public T getExtension(String name, String spiDir, String standbyDir) {\n        if (name == null || name.length() == 0) throw new IllegalArgumentException(\"Extension name == null\");\n        if (\"true\".equals(name)) {\n            return getDefaultExtension(spiDir, standbyDir);\n        }\n        Holder<Object> holder = cachedInstances.get(name);\n        if (holder == null) {\n            cachedInstances.putIfAbsent(name, new Holder<>());\n            holder = cachedInstances.get(name);\n        }\n        Object instance = holder.get();\n        if (instance == null) {\n            synchronized (holder) {\n                instance = holder.get();\n                if (instance == null) {\n                    instance = createExtension(name, spiDir, standbyDir);\n                    holder.set(instance);\n                }\n            }\n        }","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/connector/core/src/main/java/com/alibaba/otter/canal/connector/core/spi/ExtensionLoader.java#L89-L125","documentation":"Thrown by ExtensionLoader.getExtension(name, spiDir, standbyDir) (3-arg overload) when name is null or empty. This is the entry point that resolves a named extension; a null/blank name has no meaning unless it is the literal \"true\" (which selects the default). It is a caller programming error.","triggerScenarios":"Passing a null/empty extension name, e.g. reading canal.mq.mode or canal.instance.filter from config that resolved to null/blank and forwarding it to getExtension.","commonSituations":"Missing config property that maps to the extension name (e.g. canal.mq.mode not set); logic that computes the name returning null; whitespace-only value trimmed to empty.","solutions":["Supply a concrete extension name registered in META-INF/canal/<interface> (e.g. \"rocketmq\", \"kafka\", \"rabbitmq\").","Set the missing configuration property (canal.mq.mode / canal.serverMode) that drives the name.","Default the name explicitly before calling getExtension if null is a valid configuration state."],"exampleFix":"// before\nString mq = properties.getProperty(\"canal.mq.mode\"); // null\nloader.getExtension(mq, spiDir, standbyDir);\n// after\nString mq = properties.getProperty(\"canal.mq.mode\", \"rocketmq\");\nloader.getExtension(mq, spiDir, standbyDir);","handlingStrategy":"validation","validationCode":"// Resolve a non-empty name (with a default) before getExtension\nString name = properties.getProperty(\"canal.mq.mode\");\nif (name == null || name.trim().isEmpty()) {\n    name = \"rocketmq\"; // explicit default\n}\nloader.getExtension(name.trim(), spiDir, standbyDir);","typeGuard":null,"tryCatchPattern":"try {\n    loader.getExtension(name, spiDir, standbyDir);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Extension name == null\")) {\n        // config produced empty name; supply default or fail with context\n    } else throw e;\n}","preventionTips":["Always supply a default for config-driven extension names.","Validate mode/name config at startup and fail fast with the property name."],"tags":["spi","config","extension-loader"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}