MyCATApache/Mycat-Server · error · SQLNonTransientException
can't find any valid datanode : -> ->
Error message
can't find any valid datanode : -> ->
What it means
In parserBatchInsert, after computing the sharding value for each VALUES clause, the sharding algorithm (algorithm.calculate) returned null, meaning no datanode matches that sharding value. MyCat cannot route the row and throws SQLNonTransientException naming the table, partition column, and the unresolvable sharding value.
Solutions
- Check the sharding value in the message against the sharding function configuration in rule.xml and widen the rule's range/count to cover it
- Correct the application data so the partition column value is inside the configured range
- Verify sharding column name casing/backquotes matches the table config's partitionColumn
- If the value can be out of range by design, use a sharding algorithm with a default node
Example fix
// before (rule.xml range covers 0-100) INSERT INTO t(id) VALUES (500); // after (extend rule defaultNode or fix data) INSERT INTO t(id) VALUES (50);
Defensive patterns
Strategy: validation
Validate before calling
Object v = shardingValueOf(row); if (v == null || !shardingRuleCovers(v)) throw new IllegalArgumentException("sharding value not covered: " + v); Type guard
boolean isRoutableShardValue(Integer nodeIndex) { return nodeIndex != null; } Try / catch
try { route(sql); } catch (SQLNonTransientException e) { if (e.getMessage().startsWith("can't find any valid datanode")) { handleUnshardableRow(e); } else throw e; } Prevention
- Keep the sharding algorithm's value range in sync with application IDs
- Never write NULL into a partition column
- After changing rule.xml, test boundary sharding values
- Add a defaultNode to sharding functions for out-of-range values
When it happens
Trigger: statementParse -> parserBatchInsert on a sharded INSERT where the value of the partition/sharding column falls outside the ranges or enum values configured in the sharding rule (rule.xml function), so calculate() returns null.
Common situations: Sharding hash/range function configured for values 0-100 but insert uses id=500; partition column value is null, empty, or non-numeric; rule changed after data was written; autocreator generated a node count that the algorithm can't map to.
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
- can't find hint datanode
- find no Route:
- Can't find a valid data node for specified node index
- Can't find valid data node(s) for some of specified node…
- can't find any valid datanode : + tableConfig.getName() + …
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/1980f25b463ad422.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java:268
+ columnNum + " != " + valueClause.getValues().size()
+ "values:" + valueClause;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
SQLExpr expr = valueClause.getValues().get(shardingColIndex);
String shardingValue = StringUtil.removeBackquote(getShardingValue(expr));
valueClause.getValues().set(shardingColIndex, new SQLCharExpr(shardingValue));
Integer nodeIndex = algorithm.calculate(StringUtil.removeBackquote(shardingValue));
if(algorithm instanceof SlotFunction){
slotsMap.put(nodeIndex,((SlotFunction) algorithm).slotValue()) ;
}
//没找到插入的分片
if(nodeIndex == null) {
String msg = "can't find any valid datanode :" + tableName
+ " -> " + partitionColumn + " -> " + shardingValue;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(nodeValuesMap.get(nodeIndex) == null) {
nodeValuesMap.put(nodeIndex, new ArrayList<ValuesClause>());
}
nodeValuesMap.get(nodeIndex).add(valueClause);
}
RouteResultsetNode[] nodes = new RouteResultsetNode[nodeValuesMap.size()];
int count = 0;
for(Map.Entry<Integer,List<ValuesClause>> node : nodeValuesMap.entrySet()) {
Integer nodeIndex = node.getKey();
List<ValuesClause> valuesList = node.getValue();
insertStmt.getValuesList().clear();
insertStmt.getValuesList().addAll(valuesList);
// insertStmt.setValuesList(valuesList);
if(tableConfig.isDistTable()) {
nodes[count] = new RouteResultsetNode(tableConfig.getDataNodes().get(0),View on GitHub (pinned to 65f8d8beb7)