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

  1. 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
  2. Correct the application data so the partition column value is inside the configured range
  3. Verify sharding column name casing/backquotes matches the table config's partitionColumn
  4. 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

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


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)