Tencent/APIJSON · error · IllegalArgumentException
@join:value 中value不合法!必须为 &/Table0/key0,</Table1/key1,... 或
Error message
@join:value 中value不合法!必须为 &/Table0/key0,</Table1/key1,... 或 { '&/Table0/key0':{}, '</Table1/key1':{},... } 这种形式! What it means
When @join is the map form, each entry's VALUE must itself be a Map (e.g. {"&/User/id":{}}). If any value is a string/number/array/etc., IllegalArgumentException is thrown describing both accepted notations. This fires before any path parsing, i.e. it is purely a shape check on the join map.
Source
Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractParser.java:1610
}
Set<Entry<String, Object>> set = joinMap == null ? null : new LinkedHashSet<>(slashKeys);
if (set == null || set.isEmpty()) {
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);View on GitHub (pinned to 5284052872)
Solutions
- Use the plain string form if you need no per-entry options: "@join":"&/User/id"
- Keep map values as empty objects {}; put conditions in the joined table's object in the request
- Remove any scalar/array values attached to join entries
- Re-check the exact two accepted shapes in the error message
Example fix
// before
{"@join":{"&/User/id":"contactId"}}
// after
{"@join":"&/User/id","User":{"contactId@":"/User/id"}} Defensive patterns
Strategy: validation
Validate before calling
if (join instanceof Map) {
for (Object v : ((Map<?,?>) join).values()) {
if (!(v instanceof Map)) throw new IllegalArgumentException("join entry value must be {}");
}
} Type guard
boolean joinMapValuesAreObjects(Map<?,?> joinMap) {
return joinMap.values().stream().allMatch(v -> v instanceof Map);
} Prevention
- Use the string form unless per-entry options are truly needed
- Conditions go in the table object, never as join-entry values
- Validate the assembled join structure before send
When it happens
Trigger: {"@join":{"&/User/id":"userId"}} — attaching a value to a join entry; or {"@join":{"&/User/id":[]}}. Users try to supply join conditions as scalar values on the entry.
Common situations: Assuming the map form carries ON-conditions as values (conditions belong inside the table object instead); converting string form to map form while keeping string values; misreading docs examples with placeholders.
Related errors
- AbstractParser.onJoinParse join 只能是 String 或 Map<String, Ob
- @join:value 中 value 值 {} 不合法!必须为 &/Table0,</Table1/key1,@/Ta
- join:'${e.getKey()}' 对应的 ${tableKey}:value 中 value 类型不合法!必须是
- @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/c68b2f38d9e31784.
Report an issue: GitHub.