MyCATApache/Mycat-Server · error · SQLNonTransientException
parent key can't find any valid datanode
Error message
parent key can't find any valid datanode
What it means
Thrown by RouterUtil when routing a multi-table SQL statement: one of the sharded tables' route calculation produced an empty datanode set, so no valid data node exists to send the statement to. Mycat requires at least one target datanode per table in tablesRouteMap to build a RouteResultset.
Solutions
- Check rule.xml for the table's sharding algorithm and ensure the condition value maps to a valid datanode (add covering ranges/default node)
- Verify the WHERE clause value on the partition column is in the expected format (dates, numeric strings) that the algorithm accepts
- Log and inspect calculate() result of the partition function for the offending value
- Simplify the statement to a single table to confirm which table's route is empty
Example fix
// before (rule.xml missing coverage for value) <function name="sharding-by-range" class="io.mycat.route.function.AutoPartitionByLong"> <property name="mapping">0-1000=0</property> </function> // after (add range or default node covering remaining values) <function name="sharding-by-range" class="io.mycat.route.function.AutoPartitionByLong"> <property name="mapping">0-1000=0\n1001-2000=1\ndefault=0</property> </function>
Defensive patterns
Strategy: validation
Validate before calling
// Java: before issuing multi-table SQL, pre-check each table's route
for (String table : tables) {
TableConfig tc = schema.getTables().get(table.toUpperCase());
if (tc == null || tc.getDataNodes().isEmpty()) throw new IllegalStateException("no route for " + table);
} Type guard
if (tc == null || tc.getDataNodes() == null || tc.getDataNodes().isEmpty()) { return false; } Try / catch
try { rrs = route(...); } catch (SQLNonTransientException e) { if (e.getMessage().contains("valid datanode")) { LOG.warn("empty route, check rule.xml coverage", e); } throw e; } Prevention
- Ensure sharding functions cover the full value domain with a default mapping
- Keep co-located tables on identical sharding rules
- Test partition functions against boundary values in CI
When it happens
Trigger: Executing an UPDATE/DELETE/SELECT involving multiple tables where a WHERE condition on the partition column yields no matching datanode (e.g. a partition algorithm returns null or an empty route for the given column value), or the table route set ends up empty.
Common situations: Sharding function configured with rules that don't cover all possible values (e.g. mod/hash rules missing ranges); queries with conditions on a partition column value outside any configured shard range; stale or wrong rule.xml partition configuration.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- in noSharding mode schema must have default dataNode
- ruleRequired but rule is null
- bad insert sql columnSize != valueSize:values:
- can't find any valid datanode : -> ->
- find no Route:
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/7b568df6f267f322.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1312
}
Set<String> retNodesSet = new HashSet<String>();
//分库解析信息不为空
Map<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions = routeUnit.getTablesAndConditions();
if(tablesAndConditions != null && tablesAndConditions.size() > 0) {
//为分库表找路由
RouterUtil.findRouteWithcConditionsForTables(schema, rrs, tablesAndConditions, tablesRouteMap, ctx.getSql(), cachePool, isSelect);
if(rrs.isFinishedRoute()) {
return rrs;
}
}
boolean isFirstAdd = true;
for(Map.Entry<String, Set<String>> entry : tablesRouteMap.entrySet()) {
if(entry.getValue() == null || entry.getValue().size() == 0) {
throw new SQLNonTransientException("parent key can't find any valid datanode ");
} else {
if(isFirstAdd) {
retNodesSet.addAll(entry.getValue());
isFirstAdd = false;
} else {
retNodesSet.retainAll(entry.getValue());
if(retNodesSet.size() == 0) {//两个表的路由无交集
String errMsg = "invalid route in sql, multi tables found but datanode has no intersection "
+ " sql:" + ctx.getSql();
LOGGER.warn(errMsg);
throw new SQLNonTransientException(errMsg);
}
}
}
}
if(retNodesSet != null && retNodesSet.size() > 0) {
String tableName = tables.get(0);
View on GitHub (pinned to 65f8d8beb7)