MyCATApache/Mycat-Server · error · java.lang.IllegalArgumentException

route rule for table

Error message

route rule for table ${tc.getName()} is required: ${ctx.getSql()}

What it means

Thrown when a DML (typically INSERT) targets a sharded table but the SQL contains no condition/value usable by the required route rule — checkRuleRequired() fails. The table's rule-required flag demands routing input that the statement does not provide.

Solutions

  1. Always include the partition column with a valid value in INSERT statements
  2. Set ruleRequired="false" in schema.xml if routing without a rule value is acceptable (row goes to default node semantics)
  3. Add the partition column to the application's insert code/ORM mapping
  4. Use a childTable/ER config if inserts belong to a parent's shard

Example fix

-- before
INSERT INTO orders(order_id, amount) VALUES(1001, 50);
-- after (include partition column 'customer_id')
INSERT INTO orders(order_id, customer_id, amount) VALUES(1001, 5, 50);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the partition column is present in INSERT column list before sending
if (!insertColumns.contains(tc.getPartitionColumn())) throw new IllegalArgumentException("shard key required: " + tc.getPartitionColumn());

Try / catch

try { rrs = route(...); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("route rule for table")) { LOG.warn("missing partition column in statement", e); } throw e; }

Prevention

When it happens

Trigger: INSERT into a sharded table where ruleRequired=true and the statement omits the partition column, or the partition column value cannot be extracted for routing.

Common situations: INSERT statements that don't list the partition column; schema.xml sets ruleRequired="true" but applications insert rows without the shard key; batch inserts missing the column in some rows.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1395

		Map<String, Map<String, Set<ColumnRoutePair>>> tablesAndConditions = routeUnit.getTablesAndConditions();
        if(tc.isDistTable()){
            Set<String> keySet = tablesAndConditions.keySet();
            //Map.Entry<String, Map<String, Set<ColumnRoutePair>>> entry = (Entry<String, Map<String, Set<ColumnRoutePair>>>) tablesAndConditions.get(keySet.toArray()[0]);
            return routeToDistTableNode(schema,rrs,ctx.getSql(), tablesAndConditions, cachePool,isSelect, null);
        }

		if(tc.isGlobalTable()) {//全局表
			if(isSelect) {
				// global select ,not cache route result
				rrs.setCacheAble(false);
				return routeToSingleNode(rrs, getAliveRandomDataNode(tc)/*getRandomDataNode(tc)*/, ctx.getSql());
			} else {//insert into 全局表的记录
				return routeToMultiNode(false, rrs, tc.getDataNodes(), ctx.getSql(),true);
			}
		} else {//单表或者分库表
			if (!checkRuleRequired(schema, ctx, routeUnit, tc)) {
				throw new IllegalArgumentException("route rule for table "
						+ tc.getName() + " is required: " + ctx.getSql());

			}
			if(tc.getPartitionColumn() == null && !tc.isSecondLevel()) {//单表且不是childTable
//				return RouterUtil.routeToSingleNode(rrs, tc.getDataNodes().get(0),ctx.getSql());
				return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql());
			} else {
				//每个表对应的路由映射
				Map<String,Set<String>> tablesRouteMap = new HashMap<String,Set<String>>();
				if(routeUnit.getTablesAndConditions() != null && routeUnit.getTablesAndConditions().size() > 0) {
					RouterUtil.findRouteWithcConditionsForTables(schema, rrs, routeUnit.getTablesAndConditions(), tablesRouteMap, ctx.getSql(), cachePool, isSelect);
					if(rrs.isFinishedRoute()) {
						return rrs;
					}
				}

				if(tablesRouteMap.get(tableName) == null) {
					return routeToMultiNode(rrs.isCacheAble(), rrs, tc.getDataNodes(), ctx.getSql());

View on GitHub (pinned to 65f8d8beb7)