MyCATApache/Mycat-Server · error · java.sql.SQLNonTransientException
joinKey not provided
Error message
joinKey not provided :${tc.getJoinKey()},${insertStmt} What it means
When inserting into a child (ER) table, Mycat requires the joinKey column (the FK referencing the parent's partition column) to be present in the INSERT column list, because routing needs its value. getJoinKeyIndex returns -1 when the parsed insert's columns don't include joinKey, and Mycat throws SQLNonTransientException naming the missing joinKey and the statement.
Solutions
- Add the joinKey column and its value explicitly to the INSERT column list
- Verify joinKey in schema.xml matches the actual column name exactly (case included)
- Configure the ORM to always include the FK column in inserts (no 'dynamic-insert' omission for that column)
- If the column genuinely isn't needed, remove the childTable/parentKey/joinKey ER config so the table routes as a normal sharded table
Example fix
// before
INSERT INTO order_detail(item) VALUES ('x');
// after
INSERT INTO order_detail(order_id, item) VALUES (42, 'x'); Defensive patterns
Strategy: validation
Validate before calling
// Ensure the joinKey column is in the insert column list before executing
Set<String> cols = insertColumns.stream().map(String::toLowerCase).collect(toSet());
if (!cols.contains(joinKey.toLowerCase())) throw new IllegalStateException("INSERT must include joinKey " + joinKey); Try / catch
catch (SQLNonTransientException e) { if (e.getMessage().startsWith("joinKey not provided")) { /* add joinKey column and retry */ } throw e; } Prevention
- Always list child-table columns explicitly, including the FK/joinKey
- Disable dynamic-insert omission for joinKey columns in the ORM
- Keep joinKey case in SQL identical to schema.xml
When it happens
Trigger: INSERT into a childTable where tc.getJoinKey() is defined but the insert's column list omits that column (value supplied by trigger/default/ORM, or column name cased differently).
Common situations: ORMs (Hibernate/JPA) omitting columns with default values; relying on DB triggers or defaults to fill the FK; column-name case mismatch between SQL and schema.xml joinKey; explicit column lists missing the FK in bulk-load scripts.
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
- joinKey not provided :
- ChildTable multi insert not provided
- ChildTable multi insert not provided
- can't find (root) parent sharding node for sql:
- bad insert sql (sharding column: not provided,
AI-assisted analysis of MyCATApache/Mycat-Server@65f8d8beb7 (2026-09-11).
Data as JSON: /api/errors/274f2e4a7ed89aa4.
Report an issue: GitHub.
Appendix: source
Thrown at src/main/java/io/mycat/route/util/RouterUtil.java:1931
MySqlInsertStatement insertStmt = (MySqlInsertStatement) stmt;
String tableName = insertStmt.getTableName().getSimpleName().toUpperCase();
final TableConfig tc = schema.getTables().get(tableName);
if (null != tc && tc.isChildTable()) {
erFlag = true;
String sql = insertStmt.toString();
final RouteResultset rrs = new RouteResultset(sql, ServerParse.INSERT);
String joinKey = tc.getJoinKey();
//因为是Insert语句,用MySqlInsertStatement进行parse
// MySqlInsertStatement insertStmt = (MySqlInsertStatement) (new MySqlStatementParser(origSQL)).parseInsert();
//判断条件完整性,取得解析后语句列中的joinkey列的index
int joinKeyIndex = getJoinKeyIndex(insertStmt.getColumns(), joinKey);
if (joinKeyIndex == -1) {
String inf = "joinKey not provided :" + tc.getJoinKey() + "," + insertStmt;
LOGGER.warn(inf);
throw new SQLNonTransientException(inf);
}
//子表不支持批量插入
if (isMultiInsert(insertStmt)) {
String msg = "ChildTable multi insert not provided";
LOGGER.warn(msg);
throw new SQLNonTransientException(msg);
}
//取得joinkey的值
String joinKeyVal = insertStmt.getValues().getValues().get(joinKeyIndex).toString();
//解决bug #938,当关联字段的值为char类型时,去掉前后"'"
String realVal = joinKeyVal;
if (joinKeyVal.startsWith("'") && joinKeyVal.endsWith("'") && joinKeyVal.length() > 2) {
realVal = joinKeyVal.substring(1, joinKeyVal.length() - 1);
}
// try to route by ER parent partion key
//如果是二级子表(父表不再有父表),并且分片字段正好是joinkey字段,调用routeByERParentKey
RouteResultset theRrs = RouterUtil.routeByERParentKey(sc, schema, ServerParse.INSERT, sql, rrs, tc, realVal);
View on GitHub (pinned to 65f8d8beb7)