alibaba/canal · error · IllegalStateException
alarmHandlerPluginDir [%s] can't find any name endswith ".ja
Error message
alarmHandlerPluginDir [%s] can't find any name endswith ".jar" file.
What it means
Thrown inside initAlarmHandler() (CanalInstanceWithManager.java:110-112) when both canal.alarm.handler.class and canal.alarm.handler.plugin.dir are configured, but the plugin directory either does not exist or contains no files ending in '.jar'. File.listFiles returns null for a non-existent/non-directory path, or an empty array if the dir has no jars; either triggers IllegalStateException, which is then caught and rethrown as CanalException (see error 345). The check exists because canal dynamically loads the alarm handler from a URLClassLoader built from those jars.
Source
Thrown at instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java:111
public void start() {
// 初始化metaManager
logger.info("start CannalInstance for {}-{} with parameters:{}", canalId, destination, parameters);
super.start();
}
@SuppressWarnings("resource")
protected void initAlarmHandler() {
logger.info("init alarmHandler begin...");
String alarmHandlerClass = parameters.getAlarmHandlerClass();
String alarmHandlerPluginDir = parameters.getAlarmHandlerPluginDir();
if (alarmHandlerClass == null || alarmHandlerPluginDir == null) {
alarmHandler = new LogAlarmHandler();
} else {
try {
File externalLibDir = new File(alarmHandlerPluginDir);
File[] jarFiles = externalLibDir.listFiles((dir, name) -> name.endsWith(".jar"));
if (jarFiles == null || jarFiles.length == 0) {
throw new IllegalStateException(String.format("alarmHandlerPluginDir [%s] can't find any name endswith \".jar\" file.",
alarmHandlerPluginDir));
}
URL[] urls = new URL[jarFiles.length];
for (int i = 0; i < jarFiles.length; i++) {
urls[i] = jarFiles[i].toURI().toURL();
}
ClassLoader currentClassLoader = new URLClassLoader(urls,
CanalInstanceWithManager.class.getClassLoader());
Class<CanalAlarmHandler> _alarmClass = (Class<CanalAlarmHandler>) currentClassLoader.loadClass(alarmHandlerClass);
alarmHandler = _alarmClass.newInstance();
logger.info("init [{}] alarm handler success.", alarmHandlerClass);
} catch (Throwable e) {
String errorMsg = String.format("init alarmHandlerPluginDir [%s] alarm handler [%s] error: %s",
alarmHandlerPluginDir,
alarmHandlerClass,
ExceptionUtils.getFullStackTrace(e));
logger.error(errorMsg);
throw new CanalException(errorMsg, e);View on GitHub (pinned to 87be50e876)
Solutions
- Verify the directory exists and is readable from the canal process's working directory: ls -la <alarmHandlerPluginDir> and confirm at least one *.jar is present (lowercase).
- Use an absolute path for canal.alarm.handler.plugin.dir to avoid working-directory ambiguity.
- If the plugin dir is optional, remove canal.alarm.handler.class and canal.alarm.handler.plugin.dir to fall back to the default LogAlarmHandler.
- On case-sensitive filesystems ensure jars end in lowercase '.jar' (the filter is case-sensitive) or rename '.JAR' -> '.jar'.
Example fix
# before — wrong/relative dir canal.alarm.handler.class = com.example.MyAlarmHandler canal.alarm.handler.plugin.dir = plugin # after — absolute path containing my-alarm.jar canal.alarm.handler.class = com.example.MyAlarmHandler canal.alarm.handler.plugin.dir = /opt/canal/plugin
Defensive patterns
Strategy: validation
Validate before calling
String dir = parameters.getAlarmHandlerPluginDir();
String cls = parameters.getAlarmHandlerClass();
if (cls != null && dir != null) {
File d = new File(dir);
File[] jars = d.listFiles((f, n) -> n.toLowerCase(Locale.ROOT).endsWith(".jar"));
if (!d.isDirectory() || jars == null || jars.length == 0) {
throw new IllegalStateException(
"alarmHandlerPluginDir " + dir + " is missing or contains no .jar files");
}
} Prevention
- Use an absolute path for canal.alarm.handler.plugin.dir.
- Ensure at least one lowercase .jar exists; the filter is case-sensitive.
- In containers/k8s, verify the volume mount actually populates the dir before canal starts.
- Drop the alarmHandlerClass/plugin.dir settings entirely to fall back to the default LogAlarmHandler.
When it happens
Trigger: Setting parameters alarmHandlerClass and alarmHandlerPluginDir (non-null) and then starting the instance, when the directory path is wrong, missing, not a directory, or contains zero *.jar files. The lambda `name.endsWith(".jar")` is case-sensitive, so `.JAR` files are also excluded.
Common situations: Typo in the plugin dir path; relative path resolved against the wrong working directory (canal launches from deployer/bin, not the conf dir); plugin jar renamed/missing after deploy; case mismatch (.JAR vs .jar on case-sensitive filesystems); directory mounted empty in a container/k8s deployment.
Related errors
- init alarmHandlerPluginDir [%s] alarm handler [%s] error: %s
- load extension jar failed!
- unsupport MetaMode for {}
- master/slave Sourcing type is unmatch. %s vs %s
- unsupport SourcingType for {}
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/c06920d82f3768cd.
Report an issue: GitHub.