MyCATApache/Mycat-Server · error · SQLNonTransientException

schema: ,table: ,sql: is not allowed,because table is…

Error message

schema:${schemal},table:${table},sql:${rrs.getStatement()} is not allowed,because table is migrate switching,please wait for a moment

What it means

RouteService.checkMigrateRule throws SQLNonTransientException when a multi-node UPDATE targets a table that is currently in crc32slot data migration (switching). During migration, an update spanning more than one routed node could write to nodes whose slot ranges are being re-homed, so the write is rejected until migration completes.

Solutions

  1. Wait until the migration switch completes, then retry the statement.
  2. Narrow the UPDATE so it routes to a single node (add a slot-determining predicate like the sharding column or explicit node route).
  3. Check migration status files (datanode .properties / migrateRuleMap source) to confirm migration finished; clear stale migration rules if the migration is done.
  4. Reschedule bulk update jobs outside migration windows.

Example fix

// before
UPDATE t SET x=1 WHERE id < 1000000; -- routes to many nodes
// after
UPDATE t SET x=1 WHERE id BETWEEN 1 AND 10000; -- repeat per sharding-key range, single slot
Defensive patterns

Strategy: retry

Validate before calling

// check migration status before issuing multi-node updates
boolean migrating = MigrationStatus.isActive(schema, table);
if (migrating) { scheduleRetryAfterMigration(); }

Try / catch

try {
    execute(update);
} catch (SQLNonTransientException e) {
    if (e.getMessage().contains("migrate switching")) {
        retryWithBackoffAfterMigration();
    } else { throw e; }
}

Prevention

When it happens

Trigger: route() -> checkMigrateRule finds the table in RouteCheckRule.migrateRuleMap and the routed SQL is an UPDATE with rrs.getNodes().length > 1, i.e. the statement routes to multiple data nodes while a migration is in progress.

Common situations: Running DML through mycat while a crc32slot expansion/migration (schema data migration) is active; batch jobs issuing broad UPDATEs without slot-precise WHERE clauses during a scaling operation.

Related errors


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

Appendix: source

Thrown at src/main/java/io/mycat/route/RouteService.java:162

		if (rrs != null && sqlType == ServerParse.SELECT && rrs.isCacheAble()) {
			sqlRouteCache.putIfAbsent(cacheKey, rrs);
		}
		checkMigrateRule(schema.getName(),rrs,sqlType);
		return rrs;
	}

	 //数据迁移的切换准备阶段,需要拒绝写操作和所有的跨多节点写操作
		private   void checkMigrateRule(String schemal,RouteResultset rrs,int sqlType ) throws SQLNonTransientException {
		if(rrs!=null&&rrs.getTables()!=null){
			boolean isUpdate=isUpdateSql(sqlType);
			if(!isUpdate)return;
			ConcurrentMap<String,List<PartitionByCRC32PreSlot.Range>> tableRules= RouteCheckRule.migrateRuleMap.get(schemal.toUpperCase()) ;
			if(tableRules!=null){
			for (String table : rrs.getTables()) {
				List<PartitionByCRC32PreSlot.Range> rangeList= tableRules.get(table.toUpperCase()) ;
				if(rangeList!=null&&!rangeList.isEmpty()){
					if(rrs.getNodes().length>1&&isUpdate){
						throw new   SQLNonTransientException ("schema:"+schemal+",table:"+table+",sql:"+rrs.getStatement()+" is not allowed,because table is migrate switching,please wait for a moment");
					}
					for (PartitionByCRC32PreSlot.Range range : rangeList) {
						RouteResultsetNode[] routeResultsetNodes=	rrs.getNodes();
						for (RouteResultsetNode routeResultsetNode : routeResultsetNodes) {
							int slot=routeResultsetNode.getSlot();
							if(isUpdate&&slot>=range.start&&slot<=range.end){
								throw new   SQLNonTransientException ("schema:"+schemal+",table:"+table+",sql:"+rrs.getStatement()+" is not allowed,because table is migrate switching,please wait for a moment");

							}
						}
					}
				}
			}
			}
		}
	}

View on GitHub (pinned to 65f8d8beb7)