{"record":{"id":"c06920d82f3768cd","repo":"alibaba/canal","slug":"alarmhandlerplugindir-s-can-t-find-any-name-end","errorCode":null,"errorMessage":"alarmHandlerPluginDir [%s] can't find any name endswith \".jar\" file.","messagePattern":"alarmHandlerPluginDir \\[(.+?)\\] can't find any name endswith \"\\.jar\" file\\.","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java","lineNumber":111,"sourceCode":"    public void start() {\n        // 初始化metaManager\n        logger.info(\"start CannalInstance for {}-{} with parameters:{}\", canalId, destination, parameters);\n        super.start();\n    }\n\n    @SuppressWarnings(\"resource\")\n    protected void initAlarmHandler() {\n        logger.info(\"init alarmHandler begin...\");\n        String alarmHandlerClass = parameters.getAlarmHandlerClass();\n        String alarmHandlerPluginDir = parameters.getAlarmHandlerPluginDir();\n        if (alarmHandlerClass == null || alarmHandlerPluginDir == null) {\n            alarmHandler = new LogAlarmHandler();\n        } else {\n            try {\n                File externalLibDir = new File(alarmHandlerPluginDir);\n                File[] jarFiles = externalLibDir.listFiles((dir, name) -> name.endsWith(\".jar\"));\n                if (jarFiles == null || jarFiles.length == 0) {\n                    throw new IllegalStateException(String.format(\"alarmHandlerPluginDir [%s] can't find any name endswith \\\".jar\\\" file.\",\n                        alarmHandlerPluginDir));\n                }\n                URL[] urls = new URL[jarFiles.length];\n                for (int i = 0; i < jarFiles.length; i++) {\n                    urls[i] = jarFiles[i].toURI().toURL();\n                }\n                ClassLoader currentClassLoader = new URLClassLoader(urls,\n                    CanalInstanceWithManager.class.getClassLoader());\n                Class<CanalAlarmHandler> _alarmClass = (Class<CanalAlarmHandler>) currentClassLoader.loadClass(alarmHandlerClass);\n                alarmHandler = _alarmClass.newInstance();\n                logger.info(\"init [{}] alarm handler success.\", alarmHandlerClass);\n            } catch (Throwable e) {\n                String errorMsg = String.format(\"init alarmHandlerPluginDir [%s] alarm handler [%s] error: %s\",\n                    alarmHandlerPluginDir,\n                    alarmHandlerClass,\n                    ExceptionUtils.getFullStackTrace(e));\n                logger.error(errorMsg);\n                throw new CanalException(errorMsg, e);","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/instance/manager/src/main/java/com/alibaba/otter/canal/instance/manager/CanalInstanceWithManager.java#L93-L129","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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'."],"exampleFix":"# before — wrong/relative dir\ncanal.alarm.handler.class = com.example.MyAlarmHandler\ncanal.alarm.handler.plugin.dir = plugin\n\n# after — absolute path containing my-alarm.jar\ncanal.alarm.handler.class = com.example.MyAlarmHandler\ncanal.alarm.handler.plugin.dir = /opt/canal/plugin","handlingStrategy":"validation","validationCode":"String dir = parameters.getAlarmHandlerPluginDir();\nString cls = parameters.getAlarmHandlerClass();\nif (cls != null && dir != null) {\n    File d = new File(dir);\n    File[] jars = d.listFiles((f, n) -> n.toLowerCase(Locale.ROOT).endsWith(\".jar\"));\n    if (!d.isDirectory() || jars == null || jars.length == 0) {\n        throw new IllegalStateException(\n            \"alarmHandlerPluginDir \" + dir + \" is missing or contains no .jar files\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["configuration","plugin","alarm-handler","classpath","instance-manager"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}