{"record":{"id":"7c4bd6c0b08fb518","repo":"alibaba/canal","slug":"no-tablestore-adapter-found-for-config-key-key","errorCode":null,"errorMessage":"No tablestore adapter found for config key: {key}","messagePattern":"No tablestore adapter found for config key: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/TablestoreAdapter.java","lineNumber":65,"sourceCode":"    private TablestoreSyncService tablestoreSyncService;\n\n    private Properties                              envProperties;\n\n    private OuterAdapterConfig configuration;\n\n\n    @Override\n    public void init(OuterAdapterConfig configuration, Properties envProperties) {\n        this.envProperties = envProperties;\n        this.configuration = configuration;\n        Map<String, MappingConfig> tablestoreMappingTmp = ConfigLoader.load(envProperties);\n        // 过滤不匹配的key的配置\n        tablestoreMappingTmp.forEach((key, config) -> {\n            addConfig(key, config);\n        });\n\n        if (tablestoreMapping.isEmpty()) {\n            throw new RuntimeException(\"No tablestore adapter found for config key: \" + configuration.getKey());\n        }\n\n        tablestoreSyncService = new TablestoreSyncService();\n    }\n\n    /**\n     * 根据配置文件获得tablestorewriter的WriterConfig信息\n     * @param mappingConfig\n     * @return\n     */\n    private WriterConfig getWriterConfig(MappingConfig mappingConfig) {\n        WriterConfig config = new WriterConfig();\n        MappingConfig.DbMapping mapping = mappingConfig.getDbMapping();\n        config.setMaxBatchRowsCount(mapping.getCommitBatch());\n        config.setConcurrency(mappingConfig.getThreads());\n        config.setDispatchMode(DispatchMode.HASH_PRIMARY_KEY);\n        config.setWriteMode(WriteMode.SEQUENTIAL);\n        config.setBatchRequestType(BatchRequestType.BULK_IMPORT);","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/client-adapter/tablestore/src/main/java/com/alibaba/otter/canal/client/adapter/tablestore/TablestoreAdapter.java#L47-L83","documentation":"Thrown during TablestoreAdapter.init() when, after loading all tablestore mapping configs and filtering them through addConfig()/match(), the resulting tablestoreMapping map is empty. The match() method accepts a config only if config.outerAdapterKey equals the adapter's configuration key (sameMatch), or if outerAdapterKey is null and the adapter key starts with the auto-generated prefix derived from destination+groupId (prefixMatch). If no config passes either check, the adapter has nothing to sync and refuses to initialize.","triggerScenarios":"Initializing a TablestoreAdapter whose configuration.getKey() does not match any loaded config's outerAdapterKey, and no config qualifies for prefix matching — e.g. the adapter key in canal's main config differs from the outerAdapterKey values in the tablestore mapping YAML files.","commonSituations":"The `outerAdapterKey` in the tablestore mapping YAML does not match the adapter `key` defined in the canal application.yml; mapping files are placed in the wrong directory or not discovered by MappingConfigsLoader; the adapter key was renamed in the main config but mapping files were not updated; groupId or destination changed, breaking prefix matching.","solutions":["Verify that at least one tablestore mapping YAML file has an `outerAdapterKey` value that exactly matches the adapter `key` in canal's application.yml.","Confirm the mapping files are in the directory scanned by MappingConfigsLoader (typically conf/tablestore/ or the configured resource path).","If using auto-generated keys (no outerAdapterKey in YAML), verify the adapter key follows the prefix pattern: auto-generated prefix + destination + groupId.","Check canal logs at startup for 'Tablestore mapping config loaded:' to see which files were actually discovered."],"exampleFix":"// application.yml adapter key is 'tablestore-1'\ncanalAdapters:\n  - key: tablestore-1\n\n// mapping YAML before (key mismatch)\nouterAdapterKey: ts-instance\n\n// after\nouterAdapterKey: tablestore-1","handlingStrategy":"validation","validationCode":"// Before initializing, verify at least one config matches the adapter key\nMap<String, MappingConfig> configs = ConfigLoader.load(envProperties);\nString adapterKey = configuration.getKey();\nboolean hasMatch = configs.values().stream().anyMatch(c -> {\n    boolean same = c.getOuterAdapterKey() != null && c.getOuterAdapterKey().equalsIgnoreCase(adapterKey);\n    boolean prefix = c.getOuterAdapterKey() == null && adapterKey.startsWith(\n        StringUtils.join(new String[]{Util.AUTO_GENERATED_PREFIX, c.getDestination(), c.getGroupId()}, '-'));\n    return same || prefix;\n});\nif (!hasMatch) {\n    throw new IllegalStateException(\"No tablestore config matches adapter key: \" + adapterKey);\n}","typeGuard":"null","tryCatchPattern":"try {\n    tablestoreAdapter.init(config, envProperties);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"No tablestore adapter found\")) {\n        logger.error(\"Config key mismatch. Check outerAdapterKey in tablestore mapping YAML files.\");\n    }\n    throw e;\n}","preventionTips":["Maintain a config-key-to-adapter-key mapping document for each deployment.","Use consistent naming for outerAdapterKey across all mapping files.","Add a startup smoke-test that checks config-to-adapter key matching before production traffic."],"tags":["tablestore-adapter","config-key-mismatch","init-failure","config-error"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}