{"record":{"id":"81ec73fd521a5d85","repo":"MyCATApache/Mycat-Server","slug":"can-t-find-any-valid-datanode-tablename","errorCode":null,"errorMessage":"\"can't find any valid datanode :\" + tableName + \" -> \" + partitionColumn + \" -> \" + shardingValue","messagePattern":"\"can't find any valid datanode :\" \\+ tableName \\+ \" -> \" \\+ partitionColumn \\+ \" -> \" \\+ shardingValue","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java","lineNumber":268,"sourceCode":"\t\t\t\t\t             + columnNum + \" != \" + valueClause.getValues().size() \n\t\t\t\t\t             + \"values:\" + valueClause;\n\t\t\t\t\t\tLOGGER.warn(msg);\n\t\t\t\t\t\tthrow new SQLNonTransientException(msg);\n\t\t\t\t\t}\n\t\t\t\t\tSQLExpr expr = valueClause.getValues().get(shardingColIndex);\n\t\t\t\t\tString shardingValue = StringUtil.removeBackquote(getShardingValue(expr));\n\t\t\t\t\tvalueClause.getValues().set(shardingColIndex, new SQLCharExpr(shardingValue));\n\n\t\t\t\t\tInteger nodeIndex = algorithm.calculate(StringUtil.removeBackquote(shardingValue));\n\t\t\t\t\tif(algorithm instanceof SlotFunction){\n\t\t\t\t\t\tslotsMap.put(nodeIndex,((SlotFunction) algorithm).slotValue()) ;\n\t\t\t\t\t}\n\t\t\t\t\t//没找到插入的分片\n\t\t\t\t\tif(nodeIndex == null) {\n\t\t\t\t\t\tString msg = \"can't find any valid datanode :\" + tableName \n\t\t\t\t\t\t\t\t+ \" -> \" + partitionColumn + \" -> \" + shardingValue;\n\t\t\t\t\t\tLOGGER.warn(msg);\n\t\t\t\t\t\tthrow new SQLNonTransientException(msg);\n\t\t\t\t\t}\n\t\t\t\t\tif(nodeValuesMap.get(nodeIndex) == null) {\n\t\t\t\t\t\tnodeValuesMap.put(nodeIndex, new ArrayList<ValuesClause>());\n\t\t\t\t\t}\n\t\t\t\t\tnodeValuesMap.get(nodeIndex).add(valueClause);\n\t\t\t\t}\n\n\n\t\t\t\tRouteResultsetNode[] nodes = new RouteResultsetNode[nodeValuesMap.size()];\n\t\t\t\tint count = 0;\n\t\t\t\tfor(Map.Entry<Integer,List<ValuesClause>> node : nodeValuesMap.entrySet()) {\n\t\t\t\t\tInteger nodeIndex = node.getKey();\n\t\t\t\t\tList<ValuesClause> valuesList = node.getValue();\n\t\t\t\t\tinsertStmt.getValuesList().clear();\n\t\t\t\t\tinsertStmt.getValuesList().addAll(valuesList);\n\t\t\t\t\t// insertStmt.setValuesList(valuesList);\n\t\t\t\t\tif(tableConfig.isDistTable()) {\n\t\t\t\t\t\tnodes[count] = new RouteResultsetNode(tableConfig.getDataNodes().get(0),","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/parser/druid/impl/DruidInsertParser.java#L250-L286","documentation":"After extracting each row's sharding value, Mycat asks the partition algorithm to calculate a datanode index. When algorithm.calculate() returns null — the sharding value maps to no configured datanode (out of rule range) — the row cannot be routed, so parserBatchInsert throws SQLNonTransientException.","triggerScenarios":"Batch insert into a sharded table where a value of the partition column is outside the algorithm's valid range, e.g. an integer sharding value with no matching rule entry (mod/long rule boundaries not covering it) or an unenumerated enum/day value.","commonSituations":"Sharding rule configured for IDs 0..N but application inserts IDs beyond range (e.g. negative or very large IDs); auto-increment IDs exceeding rule bounds; date-partition rules hit by unexpected dates; rule function's map/count config smaller than actual data space.","solutions":["Extend the sharding rule (partition ranges/count) in schema.xml/rule.xml so all occurring sharding values map to a datanode","Clamp or remap sharding values at the application side before inserting","Find the offending value from the error message (tableName -> partitionColumn -> shardingValue) and correct the data","Use an algorithm with a default node or a modulo rule that covers the full value space"],"exampleFix":"// before (rule.xml)\n<function name=\"shard-long\" class=\"long\"><property name=\"count\">2</property>...</function>\n// after: use a range covering all IDs, e.g.\n<function name=\"shard-long\" class=\"long\"><property name=\"count\">4</property>...</function>\n-- or switch to a mod algorithm that always maps","handlingStrategy":"validation","validationCode":"// check every sharding value maps to a datanode before inserting\nAbstractPartitionAlgorithm alg = tableConfig.getRule().getRuleAlgorithm();\nfor (Object v : shardValues) {\n    Integer node = alg.calculate(String.valueOf(v));\n    if (node == null) {\n        throw new IllegalArgumentException(\"Sharding value out of rule range: \" + pc + \" -> \" + v);\n    }\n}","typeGuard":"static boolean allValuesRoutable(AbstractPartitionAlgorithm alg, List<String> values) {\n    return values.stream().allMatch(v -> alg.calculate(v) != null);\n}","tryCatchPattern":"try {\n    executeBatchInsert(sql);\n} catch (SQLNonTransientException e) {\n    if (e.getMessage().startsWith(\"can't find any valid datanode\")) {\n        String[] parts = e.getMessage().split(\" -> \");\n        throw new IllegalArgumentException(\"Extend sharding rule for value \" + parts[2], e);\n    }\n    throw e;\n}","preventionTips":["Define sharding rules to cover the full value space (use mod/hash when ranges are unknown)","Monitor auto-increment IDs against rule boundaries","Pre-calculate datanodes in the app to detect out-of-range values early","Re-validate rule coverage whenever ID generation or dates in data change"],"tags":["sql","mycat","sharding","partitioning"],"backgroundTag":"value-out-of-range","analyzedSha":"65f8d8beb752f935752f2a0eec0ab017facab9ef","analyzedAt":"2026-09-11T00:12:21.696Z","contentChangedAt":"2026-09-11T00:12:21.696Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}