MyCATApache/Mycat-Server · error · ConfigException
dataNode define error ,dnNames.length must…
Error message
dataNode ${dnNamePre} define error ,dnNames.length must be=databases.length*hostStrings.length What it means
Thrown by XMLSchemaLoader when a <dataNode> uses multi-value expansion (comma/$/- ranges) and the number of expanded names does not equal databases.length * hosts.length. Mycat builds the cartesian product of hosts and databases and needs exactly one name per combination.
Solutions
- Adjust the name range so dnNames.length == databases.length * hostStrings.length
- Keep all three attributes' expansion ranges consistent (e.g. dn$0-75, host$1-10, db$0-759 semantics per the in-code example)
- Simplify to a single explicit <dataNode> per node if ranges are confusing
Example fix
// before (schema.xml) <dataNode name="dn1$0-9" dataHost="localhost$1-2" database="db1" /> <!-- 10 names vs 2 combos --> // after <dataNode name="dn1$0-9" dataHost="localhost1" database="db1" /> <!-- 10 names vs 10 dbs -->
Defensive patterns
Strategy: validation
Validate before calling
// verify name count == database count * host count for expanded dataNodes
String[] dn = split(dnNamePre);
if (dn.length > 1) {
int combos = split(databaseStr).length * split(host).length;
if (dn.length != combos)
throw new IllegalStateException("dnNames=" + dn.length + " != " + combos);
} Try / catch
try {
configLoader.load();
} catch (ConfigException e) {
if (e.getMessage().contains("dnNames.length must be")) {
log.error("Align name range with databases.length * dataHosts.length for the expanded <dataNode>", e);
}
throw e;
} Prevention
- Change all three attributes (name, database, dataHost) together when adjusting expansion ranges
- Note the expansion rule: names count must equal hosts × databases
- Prefer many explicit <dataNode> elements over ranges when the math is error-prone
When it happens
Trigger: E.g. name="dn1$0-9" with dataHost="host1,host2" and database="db1" producing 10 names but 2*1=2 combinations; any name range whose split length mismatches the product of database and host counts.
Common situations: Changing one range (like dn1$0-759) without updating the others; misunderstanding the host×database expansion semantics documented in the XML comments; copy-pasted expansion expressions edited partially.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- dataNode ' ' is not found!
- dataNode define error ,attribute can't be empty
- dataNode duplicated!
- 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/77240f91c4612dc5.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/config/loader/xml/XMLSchemaLoader.java:634
Element element = (Element) list.item(i);
String dnNamePre = element.getAttribute("name");
String databaseStr = element.getAttribute("database");
String host = element.getAttribute("dataHost");
//字符串不为空
if (empty(dnNamePre) || empty(databaseStr) || empty(host)) {
throw new ConfigException("dataNode " + dnNamePre + " define error ,attribute can't be empty");
}
//dnNames(name),databases(database),hostStrings(dataHost)都可以配置多个,以',', '$', '-'区分,但是需要保证database的个数*dataHost的个数=name的个数
//多个dataHost与多个database如果写在一个标签,则每个dataHost拥有所有database
//例如:<dataNode name="dn1$0-75" dataHost="localhost$1-10" database="db$0-759" />
//则为:localhost1拥有dn1$0-75,localhost2也拥有dn1$0-75(对应db$76-151)
String[] dnNames = io.mycat.util.SplitUtil.split(dnNamePre, ',', '$', '-');
String[] databases = io.mycat.util.SplitUtil.split(databaseStr, ',', '$', '-');
String[] hostStrings = io.mycat.util.SplitUtil.split(host, ',', '$', '-');
if (dnNames.length > 1 && dnNames.length != databases.length * hostStrings.length) {
throw new ConfigException("dataNode " + dnNamePre
+ " define error ,dnNames.length must be=databases.length*hostStrings.length");
}
if (dnNames.length > 1) {
List<String[]> mhdList = mergerHostDatabase(hostStrings, databases);
for (int k = 0; k < dnNames.length; k++) {
String[] hd = mhdList.get(k);
String dnName = dnNames[k];
String databaseName = hd[1];
String hostName = hd[0];
createDataNode(dnName, databaseName, hostName);
}
} else {
createDataNode(dnNamePre, databaseStr, host);
}
}View on GitHub (pinned to 65f8d8beb7)