MyCATApache/Mycat-Server · error · java.sql.SQLNonTransientException
Can't find a valid data node for specified node index
Error message
Can't find a valid data node for specified node index :${tableConfig.getName()} -> ${tableConfig.getPartitionColumn()} -> ${pair.colValue} -> Index : ${nodeIndex} What it means
Mycat throws this SQLNonTransientException during routing when a sharding rule maps a column value to a node index that does not correspond to any configured data node for the table. The partition algorithm returned nodeIndex, but dataNodes.get(nodeIndex) was out of range or invalid, so no route can be computed and the query cannot proceed. This is a fail-fast signal that the sharding data and the rule's node count disagree.
Solutions
- Add/restore dataNode entries in schema.xml so the count covers every index the rule can return, then reload config
- Check the partition algorithm configuration (rule.xml / partition pattern file) and ensure its bucket count matches the number of dataNodes
- Identify the offending value (it is printed in the message: table -> partitionColumn -> colValue) and verify how the rule maps it; fix bad data or rule params
- For mod rules with negative/overflow hash results, upgrade or configure a hashing algorithm that returns non-negative indexes
Example fix
// before (rule returns 10, only 4 nodes) SELECT * FROM t_order WHERE user_id = 7; -- nodeIndex=10, dataNodes.size()=4 -> throws // after (schema.xml) <table name="t_order" dataNode="dn1,dn2,dn3,dn4,dn5,dn6,dn7,dn8,dn9,dn10" rule="mod-rule" />
Defensive patterns
Strategy: validation
Validate before calling
// Java: before issuing the query, check the rule's index is in range
int idx = rule.calculate(columnValue);
if (idx < 0 || idx >= tableConfig.getDataNodes().size()) {
throw new IllegalArgumentException("value " + columnValue + " maps to invalid node index " + idx);
} Try / catch
catch (SQLNonTransientException e) { log.error("route failed, check schema.xml dataNodes vs rule.xml", e); throw new RouteConfigurationException(e.getMessage(), e); } Prevention
- Keep rule bucket count and dataNode count in sync; automate a config check that maxIndex < dataNodes.size()
- After shrinking/expanding dataNodes, verify historical values still map to existing nodes
- Use hashing algorithms that mask negative int results
When it happens
Trigger: A SELECT/UPDATE with an equals condition on the partition column is routed via RouterUtil.tableRouteResultForSingleColumnRule (public RouterUtil entry); the rule algorithm (e.g. PartitionByMod, partitionDate) computes an index that is < 0 or >= tableConfig.getDataNodes().size().
Common situations: schema.xml dataNode list for the table was reduced after rows were written under a larger count (e.g. shrinking a mod-10 table to 4 nodes); a hash/date function whose max index exceeds the node list; String/hash overflow producing negative index; partition function config (partition-rules xml) referencing more nodes than exist.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Can't find valid data node(s) for some of specified node…
- can't find any valid datanode : -> ->
- can't find any valid datanode
- invalid param ,connection request db is
- dataHost not exists
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/60ade7407d441370.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1698
if(nodeIndex == null) {
String msg = "can't find any valid datanode :" + tableConfig.getName()
+ " -> " + tableConfig.getPartitionColumn() + " -> " + pair.colValue;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
ArrayList<String> dataNodes = tableConfig.getDataNodes();
String node;
if (nodeIndex >=0 && nodeIndex < dataNodes.size()) {
node = dataNodes.get(nodeIndex);
} else {
node = null;
String msg = "Can't find a valid data node for specified node index :"
+ tableConfig.getName() + " -> " + tableConfig.getPartitionColumn()
+ " -> " + pair.colValue + " -> " + "Index : " + nodeIndex;
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
if(node != null) {
if(tablesRouteMap.get(tableName) == null) {
tablesRouteMap.put(tableName, new HashSet<String>());
}
if(algorithm instanceof SlotFunction){
rrs.getDataNodeSlotMap().put(node,((SlotFunction) algorithm).slotValue());
}
tablesRouteMap.get(tableName).add(node);
}
}
if(pair.rangeValue != null) {
Integer[] nodeIndexs = algorithm
.calculateRange(pair.rangeValue.beginValue.toString(), pair.rangeValue.endValue.toString());
ArrayList<String> dataNodes = tableConfig.getDataNodes();
String node;
for(Integer idx : nodeIndexs) {
if (idx >= 0 && idx < dataNodes.size()) {
View on GitHub (pinned to 65f8d8beb7)