MyCATApache/Mycat-Server · error · IllegalArgumentException

dataNode name is null

Error message

dataNode name is null

What it means

TableConfig's constructor requires a non-null dataNode; if the dataNode parameter is null it throws IllegalArgumentException("dataNode name is null"). Every table must map to at least one data node so Mycat knows where to store and read its rows.

Solutions

  1. Add dataNode="<existing-dataNode>" to the <table> element in schema.xml.
  2. Ensure the referenced dataNode is defined before the table config is built.

Example fix

// before (schema.xml)
<table name="orders" primaryKey="id" />
// after
<table name="orders" primaryKey="id" dataNode="dn1" />
Defensive patterns

Strategy: validation

Validate before calling

if (dataNode == null || dataNode.isEmpty()) throw new IllegalArgumentException("dataNode required for table " + tableName);

Try / catch

try { TableConfig tc = new TableConfig(...); } catch (IllegalArgumentException e) { if ("dataNode name is null".equals(e.getMessage())) { LOG.error("table {} missing dataNode", tableName); } throw e; }

Prevention

When it happens

Trigger: Constructing TableConfig with dataNode == null, typically from a <table> element in schema.xml that has no dataNode attribute.

Common situations: Table entry in schema.xml missing dataNode="dn1"; programmatically generated config omitting the data node; XML loader returning null for an empty attribute.

Related errors


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

Appendix: source

Thrown at src/main/java/io/mycat/config/model/TableConfig.java:73

    private final String parentKey;
    private final String locateRTableKeySql;
    // only has one level of parent
    private final boolean secondLevel;
    private final boolean partionKeyIsPrimaryKey;

    private volatile List<SQLTableElement> tableElementList;
    private volatile String tableStructureSQL;
    private volatile Map<String, List<String>> dataNodeTableStructureSQLMap;
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(false);

    public TableConfig(String tableName, String primaryKey, boolean autoIncrement, boolean needAddLimit, int tableType,
                       String dataNode, Set<String> dbType, RuleConfig rule, boolean ruleRequired,
                       TableConfig parentTC, boolean isChildTable, String joinKey,
                       String parentKey, String subTables, boolean fetchStoreNodeByJdbc) {
        if (tableName == null) {
            throw new IllegalArgumentException("table name is null");
        } else if (dataNode == null) {
            throw new IllegalArgumentException("dataNode name is null");
        }
        this.primaryKey = primaryKey;
        this.autoIncrement = autoIncrement;
        this.needAddLimit = needAddLimit;
        this.fetchStoreNodeByJdbc = fetchStoreNodeByJdbc;
        this.tableType = tableType;
        this.dbTypes = dbType;
        if (ruleRequired && rule == null) {
            throw new IllegalArgumentException("ruleRequired but rule is null");
        }

        this.name = tableName.toUpperCase();
        String theDataNodes[] = SplitUtil.split(dataNode, ',', '$', '-');
        if (theDataNodes == null || theDataNodes.length <= 0) {
            throw new IllegalArgumentException("invalid table dataNodes: " + dataNode);
        }
        dataNodes = new ArrayList<String>(theDataNodes.length);
        for (String dn : theDataNodes) {

View on GitHub (pinned to 65f8d8beb7)