{"record":{"id":"663f5b5a4ca434e6","repo":"alibaba/canal","slug":"not-allow-to-change-outadapterkey","errorCode":null,"errorMessage":"not allow to change outAdapterKey","messagePattern":"not allow to change outAdapterKey","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/ClickHouseAdapter.java","lineNumber":315,"sourceCode":"        }\n    }\n\n    public boolean addConfig(String fileName, MappingConfig config) {\n        if (match(config)) {\n            clickHouseMapping.put(fileName, config);\n            addSyncConfigToCache(fileName, config);\n            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,\n                    configuration.getKey());\n            return true;\n        }\n        return false;\n    }\n\n    public void updateConfig(String fileName, MappingConfig config) {\n        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()\n                .equals(configuration.getKey())) {\n            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的\n            throw new RuntimeException(\"not allow to change outAdapterKey\");\n        }\n        clickHouseMapping.put(fileName, config);\n        addSyncConfigToCache(fileName, config);\n    }\n\n    public void deleteConfig(String fileName) {\n        clickHouseMapping.remove(fileName);\n        for (Map<String, MappingConfig> configMap : mappingConfigCache.values()) {\n            if (configMap != null) {\n                configMap.remove(fileName);\n            }\n        }\n        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);\n    }\n\n    private boolean match(MappingConfig config) {\n        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()\n                .equalsIgnoreCase(configuration.getKey());","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/client-adapter/clickhouse/src/main/java/com/alibaba/otter/canal/client/adapter/clickhouse/ClickHouseAdapter.java#L297-L333","documentation":"Thrown by ClickHouseAdapter.updateConfig during hot config reload. The new config's outerAdapterKey differs from the adapter's own configuration.getKey(). outerAdapterKey is the immutable binding between a mapping config and its adapter instance; changing it at runtime would orphan the config from its adapter, so it is forbidden.","triggerScenarios":"The ClickHouseConfigMonitor detects a changed mapping file and calls updateConfig, but the edited file's outerAdapterKey was changed to a different adapter key; editing the yml's outerAdapterKey field while the adapter is running.","commonSituations":"Operator edits a hot-reloaded mapping file and changes outerAdapterKey to repoint it to another adapter; copy-pasting a config from one adapter to another without fixing the key; misconfigured config-management tooling that rewrites keys.","solutions":["Keep outerAdapterKey stable across hot edits; do not change it on a running adapter.","To repoint a config to a different adapter, delete it from this adapter and add it to the target adapter instead.","If the key truly changed intentionally, restart the adapter rather than relying on hot reload.","Audit config-management/CI outputs to ensure outerAdapterKey is not rewritten."],"exampleFix":"# before (hot edit changes the key):\n# outerAdapterKey: clickhouse-2   <- was clickhouse-1\n# after (keep the key, restart to repoint):\n# leave outerAdapterKey: clickhouse-1 unchanged in the file;\n# to repoint, stop adapter, move file, restart with the new adapter.","handlingStrategy":"validation","validationCode":"// In a pre-commit/CI check on hot-reloaded config files, forbid outerAdapterKey changes:\nString oldKey = existingConfig.getOuterAdapterKey();\nString newKey = incomingConfig.getOuterAdapterKey();\nif (oldKey != null && newKey != null && !oldKey.equals(newKey)) {\n    throw new IllegalStateException(\"Refusing to change outerAdapterKey (\" + oldKey + \" -> \" + newKey + \"); restart to repoint.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    adapter.updateConfig(fileName, newConfig);\n} catch (RuntimeException e) {\n    if (e.getMessage().contains(\"not allow to change outAdapterKey\")) {\n        logger.error(\"Hot edit changed outerAdapterKey in {}; revert or restart the adapter.\", fileName);\n    }\n    throw e;\n}","preventionTips":["Never edit outerAdapterKey on a running adapter via hot reload.","To repoint a config, stop the adapter, move/update the file, then restart.","Audit config-management tools so they do not rewrite outerAdapterKey.","Keep outerAdapterKey consistent across versions of a mapping file."],"tags":["clickhouse-adapter","canal-adapter","config","hot-reload","runtime-mutation"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}