{"record":{"id":"7b568df6f267f322","repo":"MyCATApache/Mycat-Server","slug":"parent-key-can-t-find-any-valid-datanode","errorCode":null,"errorMessage":"parent key can't find any valid datanode ","messagePattern":"parent key can't find any valid datanode ","errorType":"exception","errorClass":"SQLNonTransientException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/mycat/route/util/RouterUtil.java","lineNumber":1312,"sourceCode":"\t\t}\r\n\r\n\t\tSet<String> retNodesSet = new HashSet<String>();\r\n\r\n\t\t//分库解析信息不为空\r\n\t\tMap<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions = routeUnit.getTablesAndConditions();\r\n\t\tif(tablesAndConditions != null && tablesAndConditions.size() > 0) {\r\n\t\t\t//为分库表找路由\r\n\t\t\tRouterUtil.findRouteWithcConditionsForTables(schema, rrs, tablesAndConditions, tablesRouteMap, ctx.getSql(), cachePool, isSelect);\r\n\t\t\tif(rrs.isFinishedRoute()) {\r\n\t\t\t\treturn rrs;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\r\n\t\tboolean isFirstAdd = true;\r\n\t\tfor(Map.Entry<String, Set<String>> entry : tablesRouteMap.entrySet()) {\r\n\t\t\tif(entry.getValue() == null || entry.getValue().size() == 0) {\r\n\t\t\t\tthrow new SQLNonTransientException(\"parent key can't find any valid datanode \");\r\n\t\t\t} else {\r\n\t\t\t\tif(isFirstAdd) {\r\n\t\t\t\t\tretNodesSet.addAll(entry.getValue());\r\n\t\t\t\t\tisFirstAdd = false;\r\n\t\t\t\t} else {\r\n\t\t\t\t\tretNodesSet.retainAll(entry.getValue());\r\n\t\t\t\t\tif(retNodesSet.size() == 0) {//两个表的路由无交集\r\n\t\t\t\t\t\tString errMsg = \"invalid route in sql, multi tables found but datanode has no intersection \"\r\n\t\t\t\t\t\t\t\t+ \" sql:\" + ctx.getSql();\r\n\t\t\t\t\t\tLOGGER.warn(errMsg);\r\n\t\t\t\t\t\tthrow new SQLNonTransientException(errMsg);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif(retNodesSet != null && retNodesSet.size() > 0) {\r\n\t\t\tString tableName = tables.get(0);\r","sourceCodeStart":1294,"sourceCodeEnd":1330,"githubUrl":"https://github.com/MyCATApache/Mycat-Server/blob/65f8d8beb752f935752f2a0eec0ab017facab9ef/src/main/java/io/mycat/route/util/RouterUtil.java#L1294-L1330","documentation":"Thrown by RouterUtil when routing a multi-table SQL statement: one of the sharded tables' route calculation produced an empty datanode set, so no valid data node exists to send the statement to. Mycat requires at least one target datanode per table in tablesRouteMap to build a RouteResultset.","triggerScenarios":"Executing an UPDATE/DELETE/SELECT involving multiple tables where a WHERE condition on the partition column yields no matching datanode (e.g. a partition algorithm returns null or an empty route for the given column value), or the table route set ends up empty.","commonSituations":"Sharding function configured with rules that don't cover all possible values (e.g. mod/hash rules missing ranges); queries with conditions on a partition column value outside any configured shard range; stale or wrong rule.xml partition configuration.","solutions":["Check rule.xml for the table's sharding algorithm and ensure the condition value maps to a valid datanode (add covering ranges/default node)","Verify the WHERE clause value on the partition column is in the expected format (dates, numeric strings) that the algorithm accepts","Log and inspect calculate() result of the partition function for the offending value","Simplify the statement to a single table to confirm which table's route is empty"],"exampleFix":"// before (rule.xml missing coverage for value)\n<function name=\"sharding-by-range\" class=\"io.mycat.route.function.AutoPartitionByLong\">\n  <property name=\"mapping\">0-1000=0</property>\n</function>\n// after (add range or default node covering remaining values)\n<function name=\"sharding-by-range\" class=\"io.mycat.route.function.AutoPartitionByLong\">\n  <property name=\"mapping\">0-1000=0\\n1001-2000=1\\ndefault=0</property>\n</function>","handlingStrategy":"validation","validationCode":"// Java: before issuing multi-table SQL, pre-check each table's route\nfor (String table : tables) {\n    TableConfig tc = schema.getTables().get(table.toUpperCase());\n    if (tc == null || tc.getDataNodes().isEmpty()) throw new IllegalStateException(\"no route for \" + table);\n}","typeGuard":"if (tc == null || tc.getDataNodes() == null || tc.getDataNodes().isEmpty()) { return false; }","tryCatchPattern":"try { rrs = route(...); } catch (SQLNonTransientException e) { if (e.getMessage().contains(\"valid datanode\")) { LOG.warn(\"empty route, check rule.xml coverage\", e); } throw e; }","preventionTips":["Ensure sharding functions cover the full value domain with a default mapping","Keep co-located tables on identical sharding rules","Test partition functions against boundary values in CI"],"tags":["routing","sharding","mycat"],"backgroundTag":"resource-not-found","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"}