MyCATApache/Mycat-Server · error · java.sql.SQLNonTransientException

can't find any valid datanode

Error message

can't find any valid datanode :${tableConfig.getName()} -> ${tableConfig.getPartitionColumn()} -> ${pair.colValue}

What it means

Thrown during dist-table routing when the sharding algorithm's calculate(colValue) returns null for a partition-column value, meaning no sub-table index maps to that value. Mycat cannot determine which dist sub-table holds the row.

Solutions

  1. Extend the rule mapping in rule.xml to cover the offending value or add a default mapping
  2. Fix the client to send partition-column values in the format the algorithm expects (e.g. 'YYYYMMDD' for date rules)
  3. Test the partition function standalone with the failing value to confirm calculate() behavior
  4. Reject or sanitize such values at the application layer before queries

Example fix

// before
Integer tableIndex = algorithm.calculate(pair.colValue); // null for '2026-13-01'
// after: guard value format before routing
if (pair.colValue == null || !pair.colValue.matches("\\d{8}")) {
    throw new SQLNonTransientException("invalid partition value: " + pair.colValue);
}
Integer tableIndex = algorithm.calculate(pair.colValue);
Defensive patterns

Strategy: try-catch

Validate before calling

Integer idx = algorithm.calculate(value);
if (idx == null) throw new IllegalArgumentException("no dist sub-table for value: " + value);

Try / catch

try { rrs = route(...); } catch (SQLNonTransientException e) { if (e.getMessage().startsWith("can't find any valid datanode")) { LOG.warn("partition value unmapped, check rule.xml: " + e.getMessage()); } throw e; }

Prevention

When it happens

Trigger: A condition or insert value on the table's partition column is passed to algorithm.calculate() and returns null (value outside configured ranges, wrong format, e.g. non-numeric string for a numeric rule).

Common situations: Dist table rules in rule.xml with ranges that don't cover all values; date strings in an unexpected format; null/unparseable partition values in WHERE clauses.

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


AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11). Data as JSON: /api/errors/95d9f939f355ec5a. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1502

	
	private static void setNodes(RouteResultset rrs, TableConfig tableConfig, String partionCol,
        Set<String> tablesRouteSet, Map.Entry<String, Map<String, Set<ColumnRoutePair>>> entry1)
        throws SQLNonTransientException {
        Map<String, Set<ColumnRoutePair>> columnsMap = entry1.getValue();
    
        Set<ColumnRoutePair> partitionValue = columnsMap.get(partionCol);
        if(partitionValue == null || partitionValue.size() == 0) {
            tablesRouteSet.addAll(tableConfig.getDistTables());
        } else {
            for(ColumnRoutePair pair : partitionValue) {
                AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
                if(pair.colValue != null) {
                    Integer tableIndex = algorithm.calculate(pair.colValue);
                    if(tableIndex == null) {
                        String msg = "can't find any valid datanode :" + tableConfig.getName()
                                + " -> " + tableConfig.getPartitionColumn() + " -> " + pair.colValue;
                        LOGGER.warn(msg);
                        throw new SQLNonTransientException(msg);
                    }
                    String subTable = tableConfig.getDistTables().get(tableIndex);
                    if(subTable != null) {
                        tablesRouteSet.add(subTable);
                        if(algorithm instanceof SlotFunction){
                            rrs.getDataNodeSlotMap().put(subTable,((SlotFunction) algorithm).slotValue());
                        }
                    }
                }
                if(pair.rangeValue != null) {
                    Integer[] tableIndexs = algorithm
                            .calculateRange(pair.rangeValue.beginValue.toString(), pair.rangeValue.endValue.toString());
                    for(Integer idx : tableIndexs) {
                        String subTable = tableConfig.getDistTables().get(idx);
                        if(subTable != null) {
                            tablesRouteSet.add(subTable);
                            if(algorithm instanceof SlotFunction){
                                rrs.getDataNodeSlotMap().put(subTable,((SlotFunction) algorithm).slotValue());

View on GitHub (pinned to 65f8d8beb7)