alibaba/canal · critical · RuntimeException
instance=%s,groupId=%s Load OuterAdapters is Empty,pls check
Error message
instance=%s,groupId=%s Load OuterAdapters is Empty,pls check rdb.yml
What it means
Thrown by CanalAdapterLoader.init() when, after attempting to load every OuterAdapter in a group, the successfully-initialized list is empty or its size differs from group.getOuterAdapters().size(). Because all adapters in a group consume the same messages, partial init is disallowed: if any one adapter failed to initialize, the whole group is rejected. The message hardcodes 'pls check rdb.yml' but the failure can be any adapter type.
Source
Thrown at client-adapter/launcher/src/main/java/com/alibaba/otter/canal/adapter/launcher/loader/CanalAdapterLoader.java:79
// 保证一定有key
if (StringUtils.isEmpty(config.getKey())) {
String key = StringUtils.join(
new String[] { Util.AUTO_GENERATED_PREFIX, canalAdapter.getInstance(), group.getGroupId(),
String.valueOf(autoGenId) },
'-');
//gen keyId
config.setKey(key);
}
autoGenId++;
loadAdapter(config, canalOuterAdapters);
}
canalOuterAdapterGroups.add(canalOuterAdapters);
// canalOuterAdapters 存在初始化失败的情况,导致canalOuterAdapters的数量,可能小于group.getOuterAdapters
// 由于group下的 所有OuterAdapter实例都会重复消费同一批消息,因此不允许部分adapter初始化成功,必须全部初始化成功才允许消费
if(CollectionUtils.isEmpty(canalOuterAdapters) || canalOuterAdapters.size() != group.getOuterAdapters().size() ){
String msg = String.format("instance=%s,groupId=%s Load OuterAdapters is Empty,pls check rdb.yml",
canalAdapter.getInstance(),group.getGroupId());
throw new RuntimeException(msg);
}
AdapterProcessor adapterProcessor = canalAdapterProcessors.computeIfAbsent(
canalAdapter.getInstance() + "|" + StringUtils.trimToEmpty(group.getGroupId()),
f -> new AdapterProcessor(canalClientConfig,
canalAdapter.getInstance(),
group.getGroupId(),
canalOuterAdapterGroups));
adapterProcessor.start();
logger.info("Start adapter for canal-client mq topic: {} succeed",
canalAdapter.getInstance() + "-" + group.getGroupId());
}
}
}
private void loadAdapter(OuterAdapterConfig config, List<OuterAdapter> canalOutConnectors) {
try {
OuterAdapter adapter;
adapter = new ProxyOuterAdapter(loader.getExtension(config.getName(), config.getKey()));
View on GitHub (pinned to 87be50e876)
Solutions
- Read the adapter init errors logged just before this one (e.g. 'No rdb adapter found for config key', JDBC failures, 'No kudu adapter found') and fix the first failing adapter.
- Verify every outerAdapter entry in the group has correct name/key/properties and that its mapping yml files load and validate.
- Confirm the adapter SPI jar is on the classpath (a missing extension makes loadAdapter return null).
- Once all adapters in the group init cleanly, the size check passes.
Example fix
# before: second adapter fails init, group rejected
outerAdapters:
- name: logger
- name: rdb
key: mysql1
properties:
jdbc.url: jdbc:bogus # init fails -> count mismatch
# after
jdbc.url: jdbc:mysql://127.0.0.1:3306/mytest2 Defensive patterns
Strategy: validation
Validate before calling
// After building a group, check the size contract before the loader does.
List<OuterAdapter> loaded = group.getOuterAdapters().stream()
.map(this::tryLoadAdapter) // returns null on failure, logs cause
.collect(Collectors.toList());
long failures = loaded.stream().filter(Objects::isNull).count();
if (failures > 0) {
throw new IllegalStateException(
"Group " + group.getGroupId() + " has " + failures
+ " adapter(s) that failed init; fix those before starting the group");
} Prevention
- Configure each adapter in a group and verify it initializes in isolation before combining them.
- When this error fires, read the preceding adapter-specific init errors - the named 'rdb.yml' is just the default hint.
- Ensure every adapter SPI jar is on the classpath so loadAdapter never returns null.
When it happens
Trigger: loadAdapter() is called for each config in a group; one or more returns null or throws and is not added to canalOuterAdapters, so its final size is less than group.getOuterAdapters().size(). This commonly happens when an adapter's own init() throws (e.g. errors 160/166/174 'No ... adapter found', bad JDBC properties, missing SPI).
Common situations: An rdb/kudu/phoenix/es adapter in the group failed its init() due to a config or connectivity error, and loadAdapter swallowed it, shrinking the list. The wrong yml is often the real cause, even though the message only names rdb.yml.
Related errors
- No kudu adapter found for config key: {}
- No phoenix adapter found for config key: {}
- No rdb adapter found for config key: {key}
- not allow to change outAdapterKey
- KuduMapping.database
AI-assisted analysis of alibaba/canal@87be50e876 (2026-08-14).
Data as JSON: /api/errors/ec67b4b1709ce273.
Report an issue: GitHub.