{"record":{"id":"3452360844edd965","repo":"alibaba/canal","slug":"no-kudu-adapter-found-for-config-key","errorCode":null,"errorMessage":"No kudu adapter found for config key: {}","messagePattern":"No kudu adapter found for config key: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/KuduAdapter.java","lineNumber":67,"sourceCode":"        return kuduMapping;\n    }\n\n    public Map<String, Map<String, KuduMappingConfig>> getMappingConfigCache() {\n        return mappingConfigCache;\n    }\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n        Map<String, KuduMappingConfig> kuduMappingTmp = KuduMappingConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置,获取连接key，key为配置文件名称\n        kuduMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n        // 判断目标字段是否为空\n        if (kuduMapping.isEmpty()) {\n            throw new RuntimeException(\"No kudu adapter found for config key: \" + configuration.getKey());\n        }\n\n        Map<String, String> properties = configuration.getProperties();\n\n        String kudu_master = properties.get(\"kudu.master.address\");\n        kuduTemplate = new KuduTemplate(kudu_master);\n        kuduSyncService = new KuduSyncService(kuduTemplate);\n\n        kuduConfigMonitor = new KuduConfigMonitor();\n        kuduConfigMonitor.init(this, envProperties);\n    }\n\n    @Override\n    public void sync(List<Dml> dmls) {\n        if (dmls == null || dmls.isEmpty()) {\n            return;\n        }\n        for (Dml dml : dmls) {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/KuduAdapter.java#L49-L85","documentation":"Thrown by KuduAdapter.init() after it loads every kudu mapping yml and filters each through addConfig()->match(). If none of the loaded configs match this adapter's key, kuduMapping stays empty and the adapter aborts startup rather than run with nothing to sync. The thrown key is configuration.getKey(), the 'key:' declared for this adapter under canalAdapters in application.yml.","triggerScenarios":"KuduAdapter.init() runs; for every loaded KuduMappingConfig, match() returns false because outerAdapterKey is non-null and not equalsIgnoreCase(configuration.getKey()), OR outerAdapterKey is null and configuration.getKey() does not start with the auto-generated prefix built from destination+groupId. Alternatively KuduMappingConfigLoader.load() returned an empty map (no files in the kudu config dir, or every file parsed to null).","commonSituations":"The 'outerAdapterKey:' line in a kudu/*.yml file does not match the 'key:' of the kudu adapter entry in application.yml (e.g. yml says 'outerAdapterKey: kudu1' but application.yml declares 'key: kudu'). Mapping yml files placed in the wrong directory so MappingConfigsLoader.loadConfigs(\"kudu\") finds none. A YAML syntax error causes YamlUtils.ymlToObj to return null, which the loader silently skips, emptying the map.","solutions":["Open application.yml, find the kudu entry under canalAdapters[*].groups[*].outerAdapters, note its 'key:' value, and set 'outerAdapterKey:' in every kudu/*.yml to exactly that value (match is case-insensitive).","Confirm the kudu mapping yml files live in the directory MappingConfigsLoader scans for the \"kudu\" adapter name and are valid YAML.","Check startup logs: if '## kudu mapping config loaded' prints but the error still fires, the keys mismatch; if it never prints, loading failed entirely.","Remove stray whitespace/quotes around outerAdapterKey values in both files."],"exampleFix":"# application.yml\ncanalAdapters:\n  - instance: example\n    groups:\n      - groupId: g1\n        outerAdapters:\n          - name: kudu\n            key: kudu            # <-- adapter key\n# kudu/my_table.yml\nouterAdapterKey: kudu            # <-- must equal the key above","handlingStrategy":"validation","validationCode":"// Before starting the kudu adapter, assert at least one\n// loaded config matches the adapter key.\nString adapterKey = configuration.getKey(); // e.g. \"kudu\"\nboolean anyMatch = KuduMappingConfigLoader.load(envProperties)\n    .values().stream()\n    .anyMatch(c -> c.getOuterAdapterKey() != null\n        && c.getOuterAdapterKey().equalsIgnoreCase(adapterKey));\nif (!anyMatch) {\n    throw new IllegalStateException(\n        \"No kudu mapping yml has outerAdapterKey=\" + adapterKey\n        + \" - fix application.yml key or the yml before init\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep adapter 'key:' in application.yml and 'outerAdapterKey:' in every mapping yml in a single shared variable/config so they cannot diverge.","Add a startup smoke test that loads all mapping yml files and asserts each declared adapter key has >=1 matching config.","Treat an empty KuduMappingConfigLoader result as a configuration error in CI, not a silent skip."],"tags":["kudu","config","adapter-init","canal","key-mismatch"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}