MyCATApache/Mycat-Server · error · ConfigException

table rule duplicated!

Error message

table rule ${name} duplicated!

What it means

XMLRuleLoader.loadTableRules parses <tableRule> elements from rule.xml and stores them in a map keyed by the name attribute. If two tableRule elements share the same name, the second insertion is rejected with this ConfigException. The loader is fail-fast: duplicate rule names would make routing resolution ambiguous, so startup aborts.

Solutions

  1. Open rule.xml and search for duplicate <tableRule name="..."> entries; remove or rename the redundant one.
  2. If two rules need similar config, give each a unique name and reference the correct one in each table's rule attribute.
  3. After fixing, restart or reload MyCat config to confirm startup completes.

Example fix

// before (rule.xml)
<tableRule name="order-rule">
  <rule><columns>id</columns><algorithm>mod-long</algorithm></rule>
</tableRule>
<tableRule name="order-rule">
  <rule><columns>cust_id</columns><algorithm>hash-int</algorithm></rule>
</tableRule>
// after
<tableRule name="order-rule">
  <rule><columns>id</columns><algorithm>mod-long</algorithm></rule>
</tableRule>
<tableRule name="order-cust-rule">
  <rule><columns>cust_id</columns><algorithm>hash-int</algorithm></rule>
</tableRule>
Defensive patterns

Strategy: validation

Validate before calling

// Before deploying rule.xml, fail fast on duplicate tableRule names
Set<String> seen = new HashSet<>();
NodeList rules = doc.getElementsByTagName("tableRule");
for (int i = 0; i < rules.getLength(); i++) {
    String name = ((Element) rules.item(i)).getAttribute("name");
    if (!seen.add(name)) throw new IllegalStateException("duplicate tableRule: " + name);
}

Try / catch

try {
    configLoader.load();
} catch (ConfigException e) {
    if (e.getMessage().contains("duplicated!")) {
        LOG.error("rule.xml has duplicate definitions: {}", e.getMessage());
        throw new ConfigValidationException(e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Starting MyCat with a rule.xml (or overlapping rule.xml files) that defines two <tableRule name="X"> elements with the same name attribute; load() -> loadTableRules() hits tableRules.containsKey(name) on the second definition.

Common situations: Hand-editing rule.xml and copy-pasting a tableRule block without renaming it; merging config fragments from different environments; a hot-reload that appends a new rule without removing the old one.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/io/mycat/config/loader/xml/XMLRuleLoader.java:133

	 *     <rule>
	 *         <columns>create_date</columns>
	 *         <algorithm>partbymonth</algorithm>
	 *     </rule>
	 * </tableRule>
	 * @param root
	 * @throws SQLSyntaxErrorException
     */
	private void loadTableRules(Element root) throws SQLSyntaxErrorException {
		//获取每个tableRule标签
		NodeList list = root.getElementsByTagName("tableRule");
		for (int i = 0, n = list.getLength(); i < n; ++i) {
			Node node = list.item(i);
			if (node instanceof Element) {
				Element e = (Element) node;
				//先判断是否重复
				String name = e.getAttribute("name");
				if (tableRules.containsKey(name)) {
					throw new ConfigException("table rule " + name
							+ " duplicated!");
				}
				//获取rule标签
				NodeList ruleNodes = e.getElementsByTagName("rule");
				int length = ruleNodes.getLength();
				if (length > 1) {
					throw new ConfigException("only one rule can defined :"
							+ name);
				}
				//目前只处理第一个,未来可能有多列复合逻辑需求
				//RuleConfig是保存着rule与function对应关系的对象
				RuleConfig rule = loadRule((Element) ruleNodes.item(0));
				String funName = rule.getFunctionName();
				//判断function是否存在,获取function
				AbstractPartitionAlgorithm func = functions.get(funName);
				if (func == null) {
					throw new ConfigException("can't find function of name :"
							+ funName);

View on GitHub (pinned to 65f8d8beb7)