alibaba/canal · error · RuntimeException

not allow to change outAdapterKey

Error message

not allow to change outAdapterKey

What it means

Thrown by KuduAdapter.updateConfig() when a hot-reloaded kudu mapping yml carries an outerAdapterKey that differs from the key this adapter was initialized with (configuration.getKey()). The comment explains outerAdapterKey is the join between Adapter and Config and must stay fixed for the adapter's lifetime, so mutating it mid-run is rejected.

Source

Thrown at client-adapter/kudu/src/main/java/com/alibaba/otter/canal/client/adapter/kudu/KuduAdapter.java:218

        configMap.put(configName, mappingConfig);
    }

    public boolean addConfig(String fileName, KuduMappingConfig config) {
        if (match(config)) {
            kuduMapping.put(fileName, config);
            addSyncConfigToCache(fileName, config);
            FileName2KeyMapping.register(getClass().getAnnotation(SPI.class).value(), fileName,
                    configuration.getKey());
            return true;
        }
        return false;
    }

    public void updateConfig(String fileName, KuduMappingConfig config) {
        if (config.getOuterAdapterKey() != null && !config.getOuterAdapterKey()
                .equals(configuration.getKey())) {
            // 理论上不允许改这个 因为本身就是通过这个关联起Adapter和Config的
            throw new RuntimeException("not allow to change outAdapterKey");
        }
        kuduMapping.put(fileName, config);
        addSyncConfigToCache(fileName, config);
    }

    public void deleteConfig(String fileName) {
        kuduMapping.remove(fileName);
        for (Map<String, KuduMappingConfig> configMap : mappingConfigCache.values()) {
            if (configMap != null) {
                configMap.remove(fileName);
            }
        }
        FileName2KeyMapping.unregister(getClass().getAnnotation(SPI.class).value(), fileName);
    }

    private boolean match(KuduMappingConfig config) {
        boolean sameMatch = config.getOuterAdapterKey() != null && config.getOuterAdapterKey()
                .equalsIgnoreCase(configuration.getKey());

View on GitHub (pinned to 87be50e876)

Solutions

  1. Do not change 'outerAdapterKey:' in a mapping yml while the adapter is running; revert the edit so it matches the adapter's key.
  2. If the key genuinely must change, stop the adapter/launcher, update application.yml and the yml consistently, then restart so init() rebinds.
  3. Keep a single source of truth for adapter keys so hot-edits cannot diverge.

Example fix

# before (running adapter bound to key 'kudu')
outerAdapterKey: kudu2   # triggers error on hot reload
# after
outerAdapterKey: kudu    # keep stable; restart to change it
Defensive patterns

Strategy: validation

Validate before calling

// In a hot-reload path, reject key changes before calling updateConfig.
if (config.getOuterAdapterKey() != null
        && !config.getOuterAdapterKey().equals(configuration.getKey())) {
    logger.warn("Refusing to reload {}: outerAdapterKey changed ({} != {}). Restart to rebind.",
        fileName, config.getOuterAdapterKey(), configuration.getKey());
    return; // skip instead of letting updateConfig throw
}

Try / catch

try {
    adapter.updateConfig(fileName, newConfig);
} catch (RuntimeException e) {
    if (e.getMessage().contains("not allow to change outAdapterKey")) {
        logger.warn("Skipped hot reload of {}: outerAdapterKey immutable at runtime", fileName);
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: KuduConfigMonitor detects a changed kudu yml file at runtime and calls updateConfig(fileName, config); the new config's outerAdapterKey is non-null and not equal to configuration.getKey().

Common situations: An operator edits the 'outerAdapterKey:' line of a running kudu mapping file to point at a different adapter. A file is copied between adapter config dirs and the monitor reloads it under the wrong adapter.

Related errors


AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14). Data as JSON: /api/errors/eec93e9d6ef9fdee. Report an issue: GitHub.