Tencent/APIJSON · error · IllegalArgumentException

join:'${e.getKey()}' 对应的 ${tableKey}:value 中 value 类型不合法!必须是

Error message

join:'${e.getKey()}' 对应的 ${tableKey}:value 中 value 类型不合法!必须是 {} 这种 Map<String, Object> 格式!${e2.getMessage()}

What it means

After validating path grammar, the parser fetches the joined table's object from the request (optionally through arrKey) and requires it to be a Map. Lookup failure (missing object) or wrong type is caught and rethrown as IllegalArgumentException including the inner exception message — typically 'tableObj == null' when the referenced table object is absent from the request.

Source

Thrown at APIJSONORM/src/main/java/apijson/orm/AbstractParser.java:1662

			String alias = entry.getValue(); // owner
			if (StringUtil.isNotEmpty(alias, true) && StringUtil.isName(alias) == false) {
				throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":value 中 value 的 alias 值 " + alias + " 不合法!"
						+ "必须为 &/Table0,</Table1/key1,@/Table1:alias2/key2,... 或 { '&/Table0':{}, '</Table1/key1':{},... } 这种格式!"
						+ "且 Table:alias 的 alias 必须满足英文单词变量名格式!");
			}

			// 取出Table对应的JSONObject,及内部引用赋值 key:value
			M tableObj;
			M parentPathObj;	// 保留
			try {
				parentPathObj = arrKey == null ? request : JSON.get(request, arrKey);	// 保留
				tableObj = parentPathObj == null ? null : JSON.get(parentPathObj, tableKey);
				if (tableObj == null) {
					throw new NullPointerException("tableObj == null");
				}
			}
			catch (Exception e2) {
				throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + tableKey + ":value 中 value 类型不合法!" +
          			"必须是 {} 这种 Map<String, Object> 格式!" + e2.getMessage());
			}

			if (arrKey != null) {
				if (parentPathObj.get(apijson.JSONRequest.KEY_JOIN) != null) {
					throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + ":{ join: value } 中 value 不合法!" +
							"@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中不能有 join: value 键值对!");
				}

				Integer subPage = getInteger(parentPathObj, apijson.JSONRequest.KEY_PAGE);
				if (subPage != null && subPage != 0) {
					throw new IllegalArgumentException(apijson.JSONRequest.KEY_JOIN + ":'" + e.getKey() + "' 对应的 " + arrKey + ":{ page: value } 中 value 不合法!" +
							"@ APP JOIN 最多允许跨 1 层,只能是子数组,且数组对象中 page 值只能为 null 或 0 !");
				}
			}

			boolean isAppJoin = "@".equals(joinType);

View on GitHub (pinned to 5284052872)

Solutions

  1. Add the matching table object at the exact path the join references: {"@join":"&/User/id", "User":{...}}
  2. Ensure the value for that table key is a JSON object {}
  3. Verify arrKey matches: for '@/list[]/User' the request must have list[] containing User:{}
  4. Copy join paths and table keys from one source of truth to avoid drift

Example fix

// before
{"@join":"&/User/id","Moment":{}}
// after
{"@join":"&/User/id","User":{},"Moment":{}}
Defensive patterns

Strategy: validation

Validate before calling

for (String p : joinPaths) {
  String tableKey = tableSegmentOf(p);
  if (!(resolve(requestRoot, p) instanceof Map)) throw new IllegalStateException("join target object missing: " + p);
}

Type guard

boolean joinTargetObjectExists(Map<String,Object> root, String arrKey, String tableKey) {
  Map<?,?> parent = arrKey == null ? root : (Map<?,?>) root.get(arrKey);
  return parent != null && parent.get(tableKey) instanceof Map;
}

Prevention

When it happens

Trigger: "@join":"&/User/id" in a request that contains no "User":{...} object at that location; or "User": [...] / string instead of an object; or arrKey points to an array object that does not contain tableKey.

Common situations: Typos between join path and the table key; the table object nested at a different level than the path says; reusing a join clause from another request template; sending conditions for the joined table as a query string instead of an object.

Related errors


AI-assisted analysis of Tencent/APIJSON@5284052872 (2026-08-14). Data as JSON: /api/errors/0c784f44a2519042. Report an issue: GitHub.