Tencent/APIJSON · error · IllegalArgumentException
join:'${e.getKey()}' 中 ${key} 不合法 !@ APP JOIN 只允许 key@:/Tabl
Error message
join:'${e.getKey()}' 中 ${key} 不合法 !@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接! What it means
For APP JOIN ('@' join type) with an explicit ON key in the join path, the key minus its trailing '@' must satisfy StringUtil.isName (an English variable name: letter start, letters/digits/underscore). This IllegalArgumentException fires when the key body is not a valid identifier, because APP JOIN only supports simple '=' equivalence joins.
Source
Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractParser.java:1697
boolean isAppJoin = "@".equals(joinType);
M refObj = JSON.createJSONObject();
String key = index < 0 ? null : path.substring(index + 1); // id@
if (key != null) { // 指定某个 key 为 JOIN ON 条件
if (key.indexOf("@") != key.length() - 1) {
throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":" + e.getKey() + " 中 " + key + " 不合法!"
+ "必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种格式!"
+ "且 Table:alias 的 alias 必须满足英文单词变量名格式!");
}
if (tableObj.get(key) instanceof String == false) {
throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":" + e.getKey() + "' 对应的 "
+ tableKey + ":{ " + key + ": value } 中 value 类型不合法!必须为同层级引用赋值路径 String!");
}
if (isAppJoin && StringUtil.isName(key.substring(0, key.length() - 1)) == false) {
throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 中 " + key + " 不合法 !" +
"@ APP JOIN 只允许 key@:/Table/refKey 这种 = 等价连接!");
}
refObj.put(key, getString(tableObj, key));
}
Set<Entry<String, Object>> tableSet = tableObj.entrySet();
// 取出所有 join 条件
M requestObj = JSON.createJSONObject(); // (Map<String, Object>) obj.clone();
boolean matchSingle = false;
for (Entry<String, Object> tableEntry : tableSet) {
String k = tableEntry.getKey();
Object v = k == null ? null : tableEntry.getValue();
if (v == null) {
continue;
}View on GitHub (pinned to 5284052872)
Solutions
- Rename the join key inside the joined table object and the join path to a plain identifier: letters/digits/underscore, starting with a letter
- If the real column has an exotic name, map it via the column alias/dynamic-column mechanism rather than in the join key
Example fix
// before
{ 'join': '@/Comment/to-id@', 'Comment': { 'to-id@': '/User/id' } }
// after
{ 'join': '@/Comment/toId@', 'Comment': { 'toId@': '/User/id' } } Defensive patterns
Strategy: validation
Validate before calling
const NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
function checkAppJoinKey(joinPath) {
const key = joinPath.substring(joinPath.lastIndexOf('/') + 1);
if (key && key.endsWith('@') && !NAME_RE.test(key.slice(0, -1))) {
return `APP JOIN ON key '${key}' is not a valid identifier`;
}
return null;
} Type guard
const isValidOnName = (k) => /^[A-Za-z_][A-Za-z0-9_]*@$/.test(k);
Try / catch
Catch IllegalArgumentException containing 'APP JOIN 只允许 key@'; report the offending key from the message and reject the request at the client.
Prevention
- Restrict join ON keys to [A-Za-z_][A-Za-z0-9_]* before '@'
- Validate generated keys if table names come from external metadata
When it happens
Trigger: join paths like '@/Comment/to id@' (space), '@/Comment/to-id@' (hyphen), '@/Comment/to@id@' (embedded '@'), or '@/Comment/@' (empty name).
Common situations: Using DB column names with hyphens or non-ASCII characters as join keys; hand-building join path strings via string concatenation that leaves stray characters; copy-paste artifacts (spaces, punctuation) inside the key.
Related errors
- join:'${e.getKey()}' 中 ${k} 不合法 !@ APP JOIN 只允许 key@:/Table/
- join:'${e.getKey()}' 对应的 ${arrKey}:{ page: value } 中 value 不
- join:${e.getKey()} 中 ${k} 不合法!@ APP JOIN 必须有且只有一个引用赋值键值对!
- @join:'{}' 对应的 {} 不是合法的数组 key[] !@ APP JOIN 最多允许跨 1 层,只能是子数组
- join:${e.getKey()} 中 ${key} 不合法!必须为 &/Table0,</Table1/key1,@
AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14).
Data as JSON: /api/errors/01cee1a3e98b761b.
Report an issue: GitHub.