MyCATApache/Mycat-Server · error · ConfigException

readHost duplicated!

Error message

readHost ${hostName} duplicated!

What it means

Within a writeHost's <readHost> children, XMLSchemaLoader collects readHost 'host' attribute names into a HashSet and throws this ConfigException if the same host name appears twice under one writeHost. Read hostnames must be unique within their writeHost scope so the read pool can distinguish replicas.

Solutions

  1. Locate the writeHost in schema.xml whose readHost children collide and assign each readHost a unique host attribute (e.g., hostS1, hostS2)
  2. Note uniqueness is scoped per writeHost in this check, but use globally distinct names to be safe
  3. If readHosts are provisioned by automation, enforce unique names there
  4. Restart MyCat and confirm the config loads

Example fix

// before
<readHost host="hostS1" url="10.0.1.1:3306" .../>
<readHost host="hostS1" url="10.0.1.2:3306" .../>
// after
<readHost host="hostS1" url="10.0.1.1:3306" .../>
<readHost host="hostS2" url="10.0.1.2:3306" .../>
Defensive patterns

Strategy: validation

Validate before calling

// detect duplicate readHost names under each writeHost
for each writeHost element:
  Set<String> seen = new HashSet<>();
  NodeList rs = wh.getElementsByTagName("readHost");
  for (int i = 0; i < rs.getLength(); i++) {
      String h = ((Element) rs.item(i)).getAttribute("host");
      if (!seen.add(h)) throw new IllegalStateException("Duplicate readHost " + h);
  }

Type guard

null

Try / catch

try {
    schemaLoader.load();
} catch (ConfigException e) {
    LOG.error("Duplicate readHost name: " + e.getMessage());
    throw new ConfigurationException("ReadHost host attributes must be unique per writeHost", e);
}

Prevention

When it happens

Trigger: A <writeHost> element has two <readHost> children with the same host attribute; createDBHostConf produces a DBHostConfig whose getHostName() already exists in readHostNameSet.

Common situations: Copy-pasting a readHost line to add another replica without changing host="hostS1"; scripted replica provisioning reusing names; mistakenly nesting the same readHost under multiple writeHosts with identical names.

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/6e4b70af00f28886. Report an issue: GitHub.

Appendix: source

Thrown at src/main/java/io/mycat/config/loader/xml/XMLSchemaLoader.java:850

            Set<String> writeHostNameSet = new HashSet<String>(writeNodes.getLength());
            for (int w = 0; w < writeDbConfs.length; w++) {
                Element writeNode = (Element) writeNodes.item(w);
                writeDbConfs[w] = createDBHostConf(name, writeNode, dbType, dbDriver, maxCon, minCon, filters, logTime);
                if (writeHostNameSet.contains(writeDbConfs[w].getHostName())) {
                    throw new ConfigException("writeHost " + writeDbConfs[w].getHostName() + " duplicated!");
                } else {
                    writeHostNameSet.add(writeDbConfs[w].getHostName());
                }
                NodeList readNodes = writeNode.getElementsByTagName("readHost");
                //读取对应的每一个readHost
                if (readNodes.getLength() != 0) {
                    DBHostConfig[] readDbConfs = new DBHostConfig[readNodes.getLength()];
                    Set<String> readHostNameSet = new HashSet<String>(readNodes.getLength());
                    for (int r = 0; r < readDbConfs.length; r++) {
                        Element readNode = (Element) readNodes.item(r);
                        readDbConfs[r] = createDBHostConf(name, readNode, dbType, dbDriver, maxCon, minCon, filters, logTime);
                        if (readHostNameSet.contains(readDbConfs[r].getHostName())) {
                            throw new ConfigException("readHost " + readDbConfs[r].getHostName() + " duplicated!");
                        } else {
                            readHostNameSet.add(readDbConfs[r].getHostName());
                        }
                    }
                    readHostsMap.put(w, readDbConfs);
                }
            }

            DataHostConfig hostConf = new DataHostConfig(name, dbType, dbDriver,
                    writeDbConfs, readHostsMap, switchType, slaveThreshold, tempReadHostAvailable);

            hostConf.setMaxCon(maxCon);
            hostConf.setMinCon(minCon);
            hostConf.setBalance(balance);
            hostConf.setBalanceType(balanceType);
            hostConf.setWriteType(writeType);
            hostConf.setHearbeatSQL(heartbeatSQL);
            hostConf.setConnectionInitSql(initConSQL);

View on GitHub (pinned to 65f8d8beb7)