MyCATApache/Mycat-Server · error · SQLNonTransientException
"can't find table define of " + table + " in schema:" +…
Error message
"can't find table define of " + table + " in schema:" + schema.getName()
What it means
Mycat's LOCK TABLES statement parser requires the locked table to be defined in the current logical schema's table configuration. When the parsed table name (uppercased) is not found in schema.getTables(), routing is impossible, so a SQLNonTransientException is thrown after logging a warning.
Solutions
- Add the table to schema.xml as a <table> entry in the schema being used, then reload the Mycat config
- Verify the table name in the LOCK TABLES statement exactly matches the configured table name (parser compares uppercased names)
- Route LOCK TABLES statements to a backend MySQL directly instead of through Mycat, as support is limited to WRITE/READ lock types on configured tables
Example fix
<!-- before: schema.xml missing table --> <schema name="db1"> <table name="t_user" dataNode="dn1"/> </schema> <!-- after: table locked by the app is declared --> <schema name="db1"> <table name="t_user" dataNode="dn1"/> <table name="t_lock" dataNode="dn1"/> </schema>
Defensive patterns
Strategy: validation
Validate before calling
TableConfig tc = schema.getTables().get(tableName.toUpperCase());
if (tc == null) throw new IllegalStateException("table not in mycat schema.xml: " + tableName); Type guard
if (schema != null && schema.getTables() != null && schema.getTables().containsKey(table.toUpperCase())) { ... } Try / catch
try { route(...); } catch (SQLNonTransientException e) { if (e.getMessage().startsWith("can't find table define")) { fixSchemaConfig(); } else throw e; } Prevention
- Declare every table your app locks in schema.xml
- Keep table names consistent in case between SQL and config
- Reload Mycat config after schema.xml edits
- Prefer direct backend connections for admin/maintenance SQL like LOCK TABLES
When it happens
Trigger: Executing `LOCK TABLES <name> WRITE|READ` where <name> is not declared in the schema's <table> entries in schema.xml, or the statement's table name differs in case/format from the configured table name.
Common situations: Locking a table that exists only on the backend MySQL but was never added to Mycat's schema.xml; typos or case mismatches between the SQL table name and the configured logical table; running LOCK TABLES against Mycat-managed schemas without configuring the table as a sharding/global table.
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
- "lock type must be write or read"
- "can't find hint datanode:" + hintSQLValue
- "can't find hint schema:" + hintSQLValue
- can't find table define in schema + tableName + alias:+…
- can't find table define in schema + tableName + schema: +…
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/eb6c70aed8ab7eb6.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/parser/druid/impl/DruidLockTableParser.java:33
import io.mycat.route.parser.druid.MycatSchemaStatVisitor;
import io.mycat.server.parser.ServerParse;
import io.mycat.util.SplitUtil;
/**
* lock tables [table] [write|read]语句解析器
* @author songdabin
*/
public class DruidLockTableParser extends DefaultDruidParser implements DruidParser {
@Override
public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt)
throws SQLNonTransientException {
MySqlLockTableStatement lockTableStat = (MySqlLockTableStatement)stmt;
String table = lockTableStat.getItems().get(0).getTableSource().toString().toUpperCase();
TableConfig tableConfig = schema.getTables().get(table);
if (tableConfig == null) {
String msg = "can't find table define of " + table + " in schema:" + schema.getName();
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
LockType lockType = lockTableStat.getItems().get(0).getLockType();
if (LockType.WRITE != lockType && LockType.READ != lockType) {
String msg = "lock type must be write or read";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
List<String> dataNodes = tableConfig.getDataNodes();
RouteResultsetNode[] nodes = new RouteResultsetNode[dataNodes.size()];
for (int i = 0; i < dataNodes.size(); i ++) {
nodes[i] = new RouteResultsetNode(dataNodes.get(i), ServerParse.LOCK, stmt.toString());
}
rrs.setNodes(nodes);
rrs.setFinishedRoute(true);
}
@Override
public void visitorParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt, MycatSchemaStatVisitor visitor)View on GitHub (pinned to 65f8d8beb7)