MyCATApache/Mycat-Server · error · SQLNonTransientException
can't find table define in schema + tableName + schema: +…
Error message
can't find table define in schema + tableName + schema: + schema.getName()
What it means
RouterUtil's route-by-table-name path looks up TableConfig for the target table in the schema's table map. A null TableConfig means the table is not declared in MyCat's schema.xml, and since the schema has no single default dataNode to fall back to, it throws SQLNonTransientException.
Solutions
- Declare the table in schema.xml under the correct schema and reload the configuration
- Give the schema a default dataNode so unknown tables route to a single node
- Uppercase/normalize the table name in your SQL to match the declared name
- Confirm which MyCat schema your connection targets (SHOW DATABASES via MyCat)
Example fix
// before SELECT * FROM customer; // after (schema.xml gains) <table name="customer" dataNode="dn1" rule="rule1"/>
Defensive patterns
Strategy: validation
Validate before calling
// check MyCat sees the table before routing
ResultSet rs = stmt.executeQuery("SHOW TABLES LIKE '" + tableName.toUpperCase() + "'");
if (!rs.next()) throw new IllegalStateException("Table " + tableName + " not configured in MyCat schema.xml"); Try / catch
try {
execute(sql);
} catch (SQLNonTransientException e) {
if (e.getMessage().startsWith("can't find table define in schema")) {
// fail fast with config guidance
throw new IllegalStateException("Add <table name='...'> to schema.xml and run reload @@config", e);
}
throw e;
} Prevention
- Generate MyCat table declarations from the source DB schema in CI
- Reload config after every schema.xml change
- Use uppercase table names in SQL to match MyCat's normalized lookup
When it happens
Trigger: Executing a statement routed through this method (e.g. a routeUnit for one table) where schema.getTables().get(tableName) returns null — table absent from schema.xml for that logical schema.
Common situations: Querying a table that only exists in the backend MySQL, not declared to MyCat; case-sensitivity mismatch (MyCat compares uppercase table names); using a schema alias that lacks the table definition; config file edits not reloaded.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- can't find table define in schema + tableName + alias:+…
- can't find table define in schema + tableName + schema: +…
- "bad insert sql columnSize != valueSize:" + columnNum + "…
- bad insert sql columnSize != valueSize:values:
- "bad insert sql (sharding column:"+ partitionColumn + " not…
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/3e1eed7d2ade1b9d.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1374
}
/**
*
* 单表路由
*/
public static RouteResultset tryRouteForOneTable(SchemaConfig schema, DruidShardingParseInfo ctx,
RouteCalculateUnit routeUnit, String tableName, RouteResultset rrs, boolean isSelect,
LayerCachePool cachePool) throws SQLNonTransientException {
if (isNoSharding(schema, tableName)) {
return routeToSingleNode(rrs, schema.getDataNode(), ctx.getSql());
}
TableConfig tc = schema.getTables().get(tableName);
if(tc == null) {
String msg = "can't find table define in schema " + tableName + " schema:" + schema.getName();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
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);
}
View on GitHub (pinned to 65f8d8beb7)