Tencent/APIJSON · error · IllegalArgumentException
@join:value 中 value 值 {} 不合法!必须为 &/Table0,</Table1/key1,@/Ta
Error message
@join:value 中 value 值 {} 不合法!必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种形式! What it means
Each @join entry path must contain '/' separating join type from Table(/key): '&/User/id'. If indexOf("/") < 0 the path has no slash and IllegalArgumentException is thrown listing the required forms. This fires after the value-shape check, when the key itself is malformed.
Source
Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractParser.java:1616
Log.e(TAG, "onJoinParse set == null || set.isEmpty() >> return null;");
return null;
}
List<Join<T, M, L>> joinList = new ArrayList<>();
for (Entry<String, Object> e : set) { // { &/User:{}, </Moment/id@":{}, @/Comment/toId@:{} }
// 分割 /Table/key
String path = e == null ? null : e.getKey();
Object outer = path == null ? null : e.getValue();
if (outer instanceof Map<?, ?> == false) {
throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":value 中value不合法!"
+ "必须为 &/Table0/key0,</Table1/key1,... 或 { '&/Table0/key0':{}, '</Table1/key1':{},... } 这种形式!");
}
int index = path == null ? -1 : path.indexOf("/");
if (index < 0) {
throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":value 中 value 值 " + path + " 不合法!"
+ "必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种形式!");
}
String joinType = path.substring(0, index); //& | ! < > ( ) <> () *
// if (StringUtil.isEmpty(joinType, true)) {
// joinType = "|"; // FULL JOIN
// }
path = path.substring(index + 1);
index = path.lastIndexOf("/");
String tableKey = index < 0 ? path : path.substring(0, index); // User:owner
int index2 = tableKey.lastIndexOf("/");
String arrKey = index2 < 0 ? null : tableKey.substring(0, index2);
if (arrKey != null && isArrayKey(arrKey) == false) {
throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + " 不是合法的数组 key[] !" +
"@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!");
}
tableKey = index2 < 0 ? tableKey : tableKey.substring(index2+1);View on GitHub (pinned to 5284052872)
Solutions
- Always include the slash: '&/User', '@/Comment/toId' etc.
- Pick a valid join type prefix (& | ! < > ( ) <> () * @) before the slash
- Prefer the map form to make each path visually explicit and testable
- Add a client-side regex check like ^[&|!<>()*@]?/\w+(/\w+)?$ per entry
Example fix
// before
{"@join":"&User"}
// after
{"@join":"&/User/id"} Defensive patterns
Strategy: validation
Validate before calling
for (String p : joinPaths) {
if (!p.matches("^[&|!<>()*@]{0,2}/\\w+(:\\w+)?(/\\w+@?)?$")) throw new IllegalArgumentException("bad join path: " + p);
} Type guard
boolean joinPathHasSlash(String path) { return path != null && path.indexOf('/') > 0; } Prevention
- Generate join paths from (type, table, key) triples so a slash is always inserted
- Regex-validate every path client-side
- Prefer map form to make malformed keys visible in review
When it happens
Trigger: "@join":"&User" or map key "&User" (missing slash), or an empty-string join type without slash like "User". Also a lone '/' edge or leading whitespace corrupting indexOf.
Common situations: Omitting the join-type sigil; using '@' APP JOIN as '@User' without slash; hand-built strings; trimming or encoding steps that strip the slash.
Related errors
- @join:value 中value不合法!必须为 &/Table0/key0,</Table1/key1,... 或
- join:'${e.getKey()}' 对应的 ${tableKey}:value 中 value 类型不合法!必须是
- AbstractParser.onJoinParse join 只能是 String 或 Map<String, Ob
- @join:'{}' 对应的 {} 不是合法的数组 key[] !@ APP JOIN 最多允许跨 1 层,只能是子数组
- @join:value 中 value 的 Table 值 {} 不合法!必须为 &/Table0,</Table1/k
AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14).
Data as JSON: /api/errors/3ac361cce404dc10.
Report an issue: GitHub.